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 "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 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 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
158 return ldb_module_done(ac->req, ares->controls,
159 ares->response, ares->error);
161 return ldb_request_done(req, ares->error);
165 switch (ares->type) {
166 case LDB_REPLY_ENTRY:
168 if (ac->ares != NULL) {
170 ldb_set_errstring(ac->module->ldb,
171 "Invalid number of results while searching "
172 "for template objects");
173 ret = LDB_ERR_OPERATIONS_ERROR;
177 ac->ares = talloc_steal(ac, ares);
181 case LDB_REPLY_REFERRAL:
190 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
191 ret = samldb_next_step(ac);
193 return ldb_request_done(req, LDB_SUCCESS);
199 if (ret != LDB_SUCCESS) {
200 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
201 return ldb_module_done(ac->req, NULL, NULL, ret);
203 return ldb_request_done(req, ret);
210 static int samldb_search_template(struct samldb_ctx *ac)
212 struct event_context *ev;
213 struct loadparm_context *lparm_ctx;
214 struct ldb_context *templates_ldb;
215 char *templates_ldb_path;
216 struct ldb_request *req;
217 struct ldb_dn *basedn;
221 opaque = ldb_get_opaque(ac->module->ldb, "loadparm");
222 lparm_ctx = talloc_get_type(opaque, struct loadparm_context);
223 if (lparm_ctx == NULL) {
224 ldb_set_errstring(ac->module->ldb,
225 "Unable to find loadparm context\n");
226 return LDB_ERR_OPERATIONS_ERROR;
229 opaque = ldb_get_opaque(ac->module->ldb, "templates_ldb");
230 templates_ldb = talloc_get_type(opaque, struct ldb_context);
232 /* make sure we have the templates ldb */
233 if (!templates_ldb) {
234 templates_ldb_path = samdb_relative_path(ac->module->ldb, ac,
236 if (!templates_ldb_path) {
237 ldb_set_errstring(ac->module->ldb,
238 "samldb_init_template: ERROR: Failed "
239 "to contruct path for template db");
240 return LDB_ERR_OPERATIONS_ERROR;
243 /* NOTE: this is a request on a different database!
245 * Therefore we need to do a bloody sync call
246 * otherwise the fake event queue will never call it
247 * as it runs on the main ldb context and knows
248 * nothing about the templates_ldb one */
249 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
250 ev = ldb_get_event_context(ac->module->ldb);
252 ev = event_context_init(NULL);
254 if (!talloc_reference(templates_ldb, ev)) {
255 return LDB_ERR_OPERATIONS_ERROR;
258 templates_ldb = ldb_wrap_connect(ac->module->ldb, ev,
259 lparm_ctx, templates_ldb_path,
260 NULL, NULL, 0, NULL);
261 talloc_free(templates_ldb_path);
263 if (!templates_ldb) {
264 return LDB_ERR_OPERATIONS_ERROR;
267 ret = ldb_set_opaque(ac->module->ldb,
268 "templates_ldb", templates_ldb);
269 if (ret != LDB_SUCCESS) {
274 /* search template */
275 basedn = ldb_dn_new_fmt(ac, templates_ldb,
276 "cn=Template%s,cn=Templates", ac->type);
277 if (basedn == NULL) {
278 ldb_set_errstring(ac->module->ldb,
279 "samldb_init_template: ERROR: Failed "
280 "to contruct DN for template");
281 return LDB_ERR_OPERATIONS_ERROR;
284 /* pull the template record */
285 ret = ldb_build_search_req(&req, templates_ldb, ac,
286 basedn, LDB_SCOPE_BASE,
287 "(distinguishedName=*)", NULL,
289 ac, samldb_search_template_callback,
291 if (ret != LDB_SUCCESS) {
295 talloc_steal(req, basedn);
298 /* NOTE: this is a request on a different database!
299 * Therefore we need to do a bloody sync call
300 * otherwise the fake event queue will never call it
301 * as it runs on the main ldb context and knows
302 * nothing about the templates_ldb one */
303 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
304 return ldb_request(templates_ldb, req);
306 ret = ldb_request(templates_ldb, req);
307 if (ret != LDB_SUCCESS) {
310 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
311 if (ret != LDB_SUCCESS) {
315 return samldb_next_step(ac);
319 static int samldb_apply_template(struct samldb_ctx *ac)
321 struct ldb_message_element *el;
322 struct ldb_message *msg;
326 msg = ac->ares->message;
328 for (i = 0; i < msg->num_elements; i++) {
329 el = &msg->elements[i];
330 /* some elements should not be copied */
331 if (ldb_attr_cmp(el->name, "cn") == 0 ||
332 ldb_attr_cmp(el->name, "name") == 0 ||
333 ldb_attr_cmp(el->name, "objectClass") == 0 ||
334 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
335 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
336 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
337 ldb_attr_cmp(el->name, "objectGUID") == 0) {
340 for (j = 0; j < el->num_values; j++) {
341 ret = samdb_find_or_add_attribute(
342 ac->module->ldb, ac->msg, el->name,
343 (char *)el->values[j].data);
344 if (ret != LDB_SUCCESS) {
345 ldb_set_errstring(ac->module->ldb,
346 "Failed adding template attribute\n");
347 return LDB_ERR_OPERATIONS_ERROR;
352 return samldb_next_step(ac);
355 static int samldb_get_parent_domain(struct samldb_ctx *ac);
357 static int samldb_get_parent_domain_callback(struct ldb_request *req,
358 struct ldb_reply *ares)
360 struct samldb_ctx *ac;
364 ac = talloc_get_type(req->context, struct samldb_ctx);
367 ret = LDB_ERR_OPERATIONS_ERROR;
370 if (ares->error != LDB_SUCCESS) {
371 return ldb_module_done(ac->req, ares->controls,
372 ares->response, ares->error);
375 switch (ares->type) {
376 case LDB_REPLY_ENTRY:
378 if (ac->domain_dn != NULL) {
380 ldb_set_errstring(ac->module->ldb,
381 "Invalid number of results while searching "
382 "for domain object");
383 ret = LDB_ERR_OPERATIONS_ERROR;
387 nextRid = ldb_msg_find_attr_as_string(ares->message,
389 if (nextRid == NULL) {
390 ldb_asprintf_errstring(ac->module->ldb,
391 "attribute nextRid not found in %s\n",
392 ldb_dn_get_linearized(ares->message->dn));
393 ret = LDB_ERR_OPERATIONS_ERROR;
397 ac->next_rid = strtol(nextRid, NULL, 0);
399 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
401 if (ac->domain_sid == NULL) {
402 ldb_set_errstring(ac->module->ldb,
403 "error retrieving parent domain domain sid!\n");
404 ret = LDB_ERR_CONSTRAINT_VIOLATION;
407 ac->domain_dn = talloc_steal(ac, ares->message->dn);
413 case LDB_REPLY_REFERRAL:
422 if (ac->domain_dn == NULL) {
424 ret = samldb_get_parent_domain(ac);
427 ret = samldb_next_step(ac);
433 if (ret != LDB_SUCCESS) {
434 return ldb_module_done(ac->req, NULL, NULL, ret);
440 /* Find a domain object in the parents of a particular DN. */
441 static int samldb_get_parent_domain(struct samldb_ctx *ac)
443 static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
444 struct ldb_request *req;
448 if (ac->check_dn == NULL) {
449 return LDB_ERR_OPERATIONS_ERROR;
452 dn = ldb_dn_get_parent(ac, ac->check_dn);
454 ldb_set_errstring(ac->module->ldb,
455 "Unable to find parent domain object");
456 return LDB_ERR_CONSTRAINT_VIOLATION;
461 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
463 "(|(objectClass=domain)"
464 "(objectClass=builtinDomain)"
465 "(objectClass=samba4LocalDomain))",
468 ac, samldb_get_parent_domain_callback,
471 if (ret != LDB_SUCCESS) {
475 return ldb_next_request(ac->module, req);
478 static int samldb_generate_samAccountName(struct ldb_message *msg)
482 /* Format: $000000-000000000000 */
484 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
485 (unsigned int)generate_random(),
486 (unsigned int)generate_random(),
487 (unsigned int)generate_random());
489 return LDB_ERR_OPERATIONS_ERROR;
491 return ldb_msg_add_steal_string(msg, "samAccountName", name);
494 static int samldb_check_samAccountName_callback(struct ldb_request *req,
495 struct ldb_reply *ares)
497 struct samldb_ctx *ac;
500 ac = talloc_get_type(req->context, struct samldb_ctx);
503 ret = LDB_ERR_OPERATIONS_ERROR;
506 if (ares->error != LDB_SUCCESS) {
507 return ldb_module_done(ac->req, ares->controls,
508 ares->response, ares->error);
511 switch (ares->type) {
512 case LDB_REPLY_ENTRY:
514 /* if we get an entry it means this samAccountName
516 return ldb_module_done(ac->req, NULL, NULL,
517 LDB_ERR_ENTRY_ALREADY_EXISTS);
519 case LDB_REPLY_REFERRAL:
527 /* not found, go on */
529 ret = samldb_next_step(ac);
534 if (ret != LDB_SUCCESS) {
535 return ldb_module_done(ac->req, NULL, NULL, ret);
541 static int samldb_check_samAccountName(struct samldb_ctx *ac)
543 struct ldb_request *req;
548 if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
549 ret = samldb_generate_samAccountName(ac->msg);
550 if (ret != LDB_SUCCESS) {
555 name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
557 return LDB_ERR_OPERATIONS_ERROR;
559 filter = talloc_asprintf(ac, "samAccountName=%s", name);
560 if (filter == NULL) {
561 return LDB_ERR_OPERATIONS_ERROR;
564 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
565 ac->domain_dn, LDB_SCOPE_SUBTREE,
568 ac, samldb_check_samAccountName_callback,
571 if (ret != LDB_SUCCESS) {
575 return ldb_next_request(ac->module, req);
578 static int samldb_check_samAccountType(struct samldb_ctx *ac)
580 unsigned int account_type;
581 unsigned int group_type;
585 /* make sure sAMAccountType is not specified */
586 if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
587 ldb_asprintf_errstring(ac->module->ldb,
588 "sAMAccountType must not be specified");
589 return LDB_ERR_UNWILLING_TO_PERFORM;
592 if (strcmp("user", ac->type) == 0) {
593 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
595 ldb_asprintf_errstring(ac->module->ldb,
596 "userAccountControl invalid");
597 return LDB_ERR_UNWILLING_TO_PERFORM;
599 account_type = samdb_uf2atype(uac);
600 ret = samdb_msg_add_uint(ac->module->ldb,
604 if (ret != LDB_SUCCESS) {
609 if (strcmp("group", ac->type) == 0) {
611 group_type = samdb_result_uint(ac->msg, "groupType", 0);
612 if (group_type == 0) {
613 ldb_asprintf_errstring(ac->module->ldb,
614 "groupType invalid");
615 return LDB_ERR_UNWILLING_TO_PERFORM;
617 account_type = samdb_gtype2atype(group_type);
618 ret = samdb_msg_add_uint(ac->module->ldb,
622 if (ret != LDB_SUCCESS) {
628 return samldb_next_step(ac);
631 static int samldb_get_sid_domain_callback(struct ldb_request *req,
632 struct ldb_reply *ares)
634 struct samldb_ctx *ac;
638 ac = talloc_get_type(req->context, struct samldb_ctx);
641 ret = LDB_ERR_OPERATIONS_ERROR;
644 if (ares->error != LDB_SUCCESS) {
645 return ldb_module_done(ac->req, ares->controls,
646 ares->response, ares->error);
649 switch (ares->type) {
650 case LDB_REPLY_ENTRY:
652 if (ac->next_rid != 0) {
654 ldb_set_errstring(ac->module->ldb,
655 "Invalid number of results while searching "
656 "for domain object");
657 ret = LDB_ERR_OPERATIONS_ERROR;
661 nextRid = ldb_msg_find_attr_as_string(ares->message,
663 if (nextRid == NULL) {
664 ldb_asprintf_errstring(ac->module->ldb,
665 "attribute nextRid not found in %s\n",
666 ldb_dn_get_linearized(ares->message->dn));
667 ret = LDB_ERR_OPERATIONS_ERROR;
671 ac->next_rid = strtol(nextRid, NULL, 0);
673 ac->domain_dn = talloc_steal(ac, ares->message->dn);
679 case LDB_REPLY_REFERRAL:
687 if (ac->next_rid == 0) {
688 ldb_asprintf_errstring(ac->module->ldb,
689 "Unable to get nextRid from domain entry\n");
690 ret = LDB_ERR_OPERATIONS_ERROR;
695 ret = samldb_next_step(ac);
700 if (ret != LDB_SUCCESS) {
701 return ldb_module_done(ac->req, NULL, NULL, ret);
707 /* Find a domain object in the parents of a particular DN. */
708 static int samldb_get_sid_domain(struct samldb_ctx *ac)
710 static const char * const attrs[2] = { "nextRid", NULL };
711 struct ldb_request *req;
715 if (ac->sid == NULL) {
716 return LDB_ERR_OPERATIONS_ERROR;
719 ac->domain_sid = dom_sid_dup(ac, ac->sid);
720 if (!ac->domain_sid) {
721 return LDB_ERR_OPERATIONS_ERROR;
723 /* get the domain component part of the provided SID */
724 ac->domain_sid->num_auths--;
726 filter = talloc_asprintf(ac, "(&(objectSid=%s)"
727 "(|(objectClass=domain)"
728 "(objectClass=builtinDomain)"
729 "(objectClass=samba4LocalDomain)))",
730 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
731 if (filter == NULL) {
732 return LDB_ERR_OPERATIONS_ERROR;
735 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
736 ldb_get_default_basedn(ac->module->ldb),
740 ac, samldb_get_sid_domain_callback,
743 if (ret != LDB_SUCCESS) {
748 return ldb_next_request(ac->module, req);
751 static bool samldb_msg_add_sid(struct ldb_message *msg,
753 const struct dom_sid *sid)
756 enum ndr_err_code ndr_err;
758 ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
759 (ndr_push_flags_fn_t)ndr_push_dom_sid);
760 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
763 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
766 static int samldb_new_sid(struct samldb_ctx *ac)
769 if (ac->domain_sid == NULL || ac->next_rid == 0) {
770 return LDB_ERR_OPERATIONS_ERROR;
773 ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
774 if (ac->sid == NULL) {
775 return LDB_ERR_OPERATIONS_ERROR;
778 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
779 return LDB_ERR_OPERATIONS_ERROR;
782 return samldb_next_step(ac);
785 static int samldb_check_sid_callback(struct ldb_request *req,
786 struct ldb_reply *ares)
788 struct samldb_ctx *ac;
791 ac = talloc_get_type(req->context, struct samldb_ctx);
794 ret = LDB_ERR_OPERATIONS_ERROR;
797 if (ares->error != LDB_SUCCESS) {
798 return ldb_module_done(ac->req, ares->controls,
799 ares->response, ares->error);
802 switch (ares->type) {
803 case LDB_REPLY_ENTRY:
805 /* if we get an entry it means an object with the
806 * requested sid exists */
807 return ldb_module_done(ac->req, NULL, NULL,
808 LDB_ERR_CONSTRAINT_VIOLATION);
810 case LDB_REPLY_REFERRAL:
817 /* not found, go on */
819 ret = samldb_next_step(ac);
824 if (ret != LDB_SUCCESS) {
825 return ldb_module_done(ac->req, NULL, NULL, ret);
831 static int samldb_check_sid(struct samldb_ctx *ac)
833 const char *const attrs[2] = { "objectSid", NULL };
834 struct ldb_request *req;
838 if (ac->sid == NULL) {
839 return LDB_ERR_OPERATIONS_ERROR;
842 filter = talloc_asprintf(ac, "(objectSid=%s)",
843 ldap_encode_ndr_dom_sid(ac, ac->sid));
844 if (filter == NULL) {
845 return LDB_ERR_OPERATIONS_ERROR;
848 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
849 ldb_get_default_basedn(ac->module->ldb),
853 ac, samldb_check_sid_callback,
856 if (ret != LDB_SUCCESS) {
860 return ldb_next_request(ac->module, req);
863 static int samldb_notice_sid_callback(struct ldb_request *req,
864 struct ldb_reply *ares)
866 struct samldb_ctx *ac;
869 ac = talloc_get_type(req->context, struct samldb_ctx);
872 ret = LDB_ERR_OPERATIONS_ERROR;
875 if (ares->error != LDB_SUCCESS) {
876 return ldb_module_done(ac->req, ares->controls,
877 ares->response, ares->error);
879 if (ares->type != LDB_REPLY_DONE) {
880 ldb_set_errstring(ac->module->ldb,
881 "Invalid reply type!\n");
882 ret = LDB_ERR_OPERATIONS_ERROR;
886 ret = samldb_next_step(ac);
889 if (ret != LDB_SUCCESS) {
890 return ldb_module_done(ac->req, NULL, NULL, ret);
896 /* If we are adding new users/groups, we need to update the nextRid
897 * attribute to be 'above' the new/incoming RID. Attempt to do it
899 static int samldb_notice_sid(struct samldb_ctx *ac)
901 uint32_t old_id, new_id;
902 struct ldb_request *req;
903 struct ldb_message *msg;
904 struct ldb_message_element *els;
905 struct ldb_val *vals;
908 old_id = ac->next_rid;
909 new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
911 if (old_id >= new_id) {
912 /* no need to update the domain nextRid attribute */
913 return samldb_next_step(ac);
916 /* we do a delete and add as a single operation. That prevents
917 a race, in case we are not actually on a transaction db */
918 msg = talloc_zero(ac, struct ldb_message);
920 ldb_oom(ac->module->ldb);
921 return LDB_ERR_OPERATIONS_ERROR;
923 els = talloc_array(msg, struct ldb_message_element, 2);
925 ldb_oom(ac->module->ldb);
926 return LDB_ERR_OPERATIONS_ERROR;
928 vals = talloc_array(msg, struct ldb_val, 2);
930 ldb_oom(ac->module->ldb);
931 return LDB_ERR_OPERATIONS_ERROR;
933 msg->dn = ac->domain_dn;
934 msg->num_elements = 2;
937 els[0].num_values = 1;
938 els[0].values = &vals[0];
939 els[0].flags = LDB_FLAG_MOD_DELETE;
940 els[0].name = talloc_strdup(msg, "nextRid");
942 ldb_oom(ac->module->ldb);
943 return LDB_ERR_OPERATIONS_ERROR;
946 els[1].num_values = 1;
947 els[1].values = &vals[1];
948 els[1].flags = LDB_FLAG_MOD_ADD;
949 els[1].name = els[0].name;
951 vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
953 ldb_oom(ac->module->ldb);
954 return LDB_ERR_OPERATIONS_ERROR;
956 vals[0].length = strlen((char *)vals[0].data);
958 vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
960 ldb_oom(ac->module->ldb);
961 return LDB_ERR_OPERATIONS_ERROR;
963 vals[1].length = strlen((char *)vals[1].data);
965 ret = ldb_build_mod_req(&req, ac->module->ldb, ac,
967 ac, samldb_notice_sid_callback,
969 if (ret != LDB_SUCCESS) {
973 return ldb_next_request(ac->module, req);
976 static int samldb_add_entry_callback(struct ldb_request *req,
977 struct ldb_reply *ares)
979 struct samldb_ctx *ac;
981 ac = talloc_get_type(req->context, struct samldb_ctx);
984 return ldb_module_done(ac->req, NULL, NULL,
985 LDB_ERR_OPERATIONS_ERROR);
987 if (ares->error != LDB_SUCCESS) {
988 return ldb_module_done(ac->req, ares->controls,
989 ares->response, ares->error);
991 if (ares->type != LDB_REPLY_DONE) {
992 ldb_set_errstring(ac->module->ldb,
993 "Invalid reply type!\n");
994 return ldb_module_done(ac->req, NULL, NULL,
995 LDB_ERR_OPERATIONS_ERROR);
998 /* we exit the samldb module here */
999 return ldb_module_done(ac->req, ares->controls,
1000 ares->response, LDB_SUCCESS);
1003 static int samldb_add_entry(struct samldb_ctx *ac)
1005 struct ldb_request *req;
1008 ret = ldb_build_add_req(&req, ac->module->ldb, ac,
1011 ac, samldb_add_entry_callback,
1013 if (ret != LDB_SUCCESS) {
1017 return ldb_next_request(ac->module, req);
1020 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
1024 /* first look for the template */
1026 ret = samldb_add_step(ac, samldb_search_template);
1027 if (ret != LDB_SUCCESS) return ret;
1030 ret = samldb_add_step(ac, samldb_apply_template);
1031 if (ret != LDB_SUCCESS) return ret;
1033 /* search for a parent domain objet */
1034 ac->check_dn = ac->req->op.add.message->dn;
1035 ret = samldb_add_step(ac, samldb_get_parent_domain);
1036 if (ret != LDB_SUCCESS) return ret;
1038 /* check if we have a valid samAccountName */
1039 ret = samldb_add_step(ac, samldb_check_samAccountName);
1040 if (ret != LDB_SUCCESS) return ret;
1042 /* check account_type/group_type */
1043 ret = samldb_add_step(ac, samldb_check_samAccountType);
1044 if (ret != LDB_SUCCESS) return ret;
1046 /* check if we have a valid SID */
1047 ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1049 ret = samldb_add_step(ac, samldb_new_sid);
1050 if (ret != LDB_SUCCESS) return ret;
1052 ret = samldb_add_step(ac, samldb_get_sid_domain);
1053 if (ret != LDB_SUCCESS) return ret;
1056 ret = samldb_add_step(ac, samldb_check_sid);
1057 if (ret != LDB_SUCCESS) return ret;
1059 ret = samldb_add_step(ac, samldb_notice_sid);
1060 if (ret != LDB_SUCCESS) return ret;
1062 /* finally proceed with adding the entry */
1063 ret = samldb_add_step(ac, samldb_add_entry);
1064 if (ret != LDB_SUCCESS) return ret;
1066 return samldb_first_step(ac);
1068 /* TODO: userAccountControl, badPwdCount, codePage,
1069 * countryCode, badPasswordTime, lastLogoff, lastLogon,
1070 * pwdLastSet, primaryGroupID, accountExpires, logonCount */
1074 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
1075 struct ldb_reply *ares)
1077 struct samldb_ctx *ac;
1078 const char *nextRid;
1082 ac = talloc_get_type(req->context, struct samldb_ctx);
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(ac->module->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(ac->module->ldb,
1109 "attribute nextRid not found in %s\n",
1110 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(ac->module->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 static const char * const attrs[3] = { "nextRid", "name", NULL };
1159 struct ldb_request *req;
1163 if (ac->sid == NULL) {
1164 return LDB_ERR_OPERATIONS_ERROR;
1167 ac->domain_sid = dom_sid_dup(ac, ac->sid);
1168 if (!ac->domain_sid) {
1169 return LDB_ERR_OPERATIONS_ERROR;
1171 /* get the domain component part of the provided SID */
1172 ac->domain_sid->num_auths--;
1174 filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1175 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1176 if (filter == NULL) {
1177 return LDB_ERR_OPERATIONS_ERROR;
1180 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
1181 ldb_get_default_basedn(ac->module->ldb),
1185 ac, samldb_foreign_notice_sid_callback,
1188 if (ret != LDB_SUCCESS) {
1193 return ldb_next_request(ac->module, req);
1196 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1200 ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1201 if (ac->sid == NULL) {
1202 ac->sid = dom_sid_parse_talloc(ac->msg,
1203 (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1205 ldb_set_errstring(ac->module->ldb,
1206 "No valid found SID in "
1207 "ForeignSecurityPrincipal CN!");
1209 return LDB_ERR_CONSTRAINT_VIOLATION;
1211 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1213 return LDB_ERR_OPERATIONS_ERROR;
1217 /* first look for the template */
1218 ac->type = "foreignSecurityPrincipal";
1219 ret = samldb_add_step(ac, samldb_search_template);
1220 if (ret != LDB_SUCCESS) return ret;
1223 ret = samldb_add_step(ac, samldb_apply_template);
1224 if (ret != LDB_SUCCESS) return ret;
1226 /* check we do not already have this SID */
1227 ret = samldb_add_step(ac, samldb_check_sid);
1228 if (ret != LDB_SUCCESS) return ret;
1230 /* check if we need to notice this SID */
1231 ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1232 if (ret != LDB_SUCCESS) return ret;
1234 /* finally proceed with adding the entry */
1235 ret = samldb_add_step(ac, samldb_add_entry);
1236 if (ret != LDB_SUCCESS) return ret;
1238 return samldb_first_step(ac);
1241 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1243 const char *rdn_name;
1245 rdn_name = ldb_dn_get_rdn_name(dn);
1247 if (strcasecmp(rdn_name, "cn") != 0) {
1248 ldb_asprintf_errstring(module->ldb,
1249 "Bad RDN (%s=) for samldb object, "
1250 "should be CN=!\n", rdn_name);
1251 return LDB_ERR_CONSTRAINT_VIOLATION;
1258 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1260 struct samldb_ctx *ac;
1263 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1265 /* do not manipulate our control entries */
1266 if (ldb_dn_is_special(req->op.add.message->dn)) {
1267 return ldb_next_request(module, req);
1270 ac = samldb_ctx_init(module, req);
1272 return LDB_ERR_OPERATIONS_ERROR;
1275 /* build the new msg */
1276 ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1279 ldb_debug(ac->module->ldb, LDB_DEBUG_FATAL,
1280 "samldb_add: ldb_msg_copy failed!\n");
1281 return LDB_ERR_OPERATIONS_ERROR;
1284 if (samdb_find_attribute(module->ldb, ac->msg,
1285 "objectclass", "computer") != NULL) {
1287 /* make sure the computer object also has the 'user'
1288 * objectclass so it will be handled by the next call */
1289 ret = samdb_find_or_add_value(module->ldb, ac->msg,
1290 "objectclass", "user");
1291 if (ret != LDB_SUCCESS) {
1297 if (samdb_find_attribute(module->ldb, ac->msg,
1298 "objectclass", "user") != NULL) {
1300 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1301 if (ret != LDB_SUCCESS) {
1306 return samldb_fill_object(ac, "user");
1309 if (samdb_find_attribute(module->ldb, ac->msg,
1310 "objectclass", "group") != NULL) {
1312 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1313 if (ret != LDB_SUCCESS) {
1318 return samldb_fill_object(ac, "group");
1321 /* perhaps a foreignSecurityPrincipal? */
1322 if (samdb_find_attribute(module->ldb, ac->msg,
1324 "foreignSecurityPrincipal") != NULL) {
1326 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1327 if (ret != LDB_SUCCESS) {
1332 return samldb_fill_foreignSecurityPrincipal_object(ac);
1337 /* nothing matched, go on */
1338 return ldb_next_request(module, req);
1342 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1344 struct ldb_message *msg;
1345 struct ldb_message_element *el, *el2;
1347 unsigned int group_type, user_account_control, account_type;
1348 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1349 return ldb_next_request(module, req);
1352 if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1353 ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified");
1354 return LDB_ERR_UNWILLING_TO_PERFORM;
1357 /* TODO: do not modify original request, create a new one */
1359 el = ldb_msg_find_element(req->op.mod.message, "groupType");
1360 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1361 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1363 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1364 account_type = samdb_gtype2atype(group_type);
1365 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1368 if (ret != LDB_SUCCESS) {
1371 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1372 el2->flags = LDB_FLAG_MOD_REPLACE;
1375 el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1376 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1377 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1379 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1380 account_type = samdb_uf2atype(user_account_control);
1381 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1384 if (ret != LDB_SUCCESS) {
1387 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1388 el2->flags = LDB_FLAG_MOD_REPLACE;
1390 return ldb_next_request(module, req);
1394 static int samldb_init(struct ldb_module *module)
1396 return ldb_next_init(module);
1399 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1401 .init_context = samldb_init,
1403 .modify = samldb_modify