4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
5 Copyright (C) Simo Sorce 2004-2008
7 * NOTICE: this module is NOT released under the GNU LGPL license as
8 * other ldb code. This module is release under the GNU GPL v3 or
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * Component: ldb samldb module
30 * Description: add embedded user/group creation functionality
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "lib/ldb/include/ldb_errors.h"
38 #include "lib/ldb/include/ldb.h"
39 #include "lib/ldb/include/ldb_private.h"
40 #include "lib/events/events.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "libcli/security/security.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "../lib/util/util_ldb.h"
49 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
52 struct samldb_step *next;
57 struct ldb_module *module;
58 struct ldb_request *req;
60 /* the resulting message */
61 struct ldb_message *msg;
63 /* used to apply templates */
66 /* used to find parent domain */
67 struct ldb_dn *check_dn;
68 struct ldb_dn *domain_dn;
69 struct dom_sid *domain_sid;
72 /* generic storage, remember to zero it before use */
73 struct ldb_reply *ares;
75 /* holds the entry SID */
78 /* all the async steps necessary to complete the operation */
79 struct samldb_step *steps;
80 struct samldb_step *curstep;
83 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
84 struct ldb_request *req)
86 struct samldb_ctx *ac;
88 ac = talloc_zero(req, struct samldb_ctx);
100 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
102 struct samldb_step *step;
104 step = talloc_zero(ac, struct samldb_step);
106 return LDB_ERR_OPERATIONS_ERROR;
109 if (ac->steps == NULL) {
113 ac->curstep->next = step;
122 static int samldb_first_step(struct samldb_ctx *ac)
124 if (ac->steps == NULL) {
125 return LDB_ERR_OPERATIONS_ERROR;
128 ac->curstep = ac->steps;
129 return ac->curstep->fn(ac);
132 static int samldb_next_step(struct samldb_ctx *ac)
134 if (ac->curstep->next) {
135 ac->curstep = ac->curstep->next;
136 return ac->curstep->fn(ac);
139 /* it is an error if the last step does not properly
140 * return to the upper module by itself */
141 return LDB_ERR_OPERATIONS_ERROR;
144 static int samldb_search_template_callback(struct ldb_request *req,
145 struct ldb_reply *ares)
147 struct samldb_ctx *ac;
150 ac = talloc_get_type(req->context, struct samldb_ctx);
153 ret = LDB_ERR_OPERATIONS_ERROR;
156 if (ares->error != LDB_SUCCESS) {
157 return ldb_module_done(ac->req, ares->controls,
158 ares->response, ares->error);
161 switch (ares->type) {
162 case LDB_REPLY_ENTRY:
164 if (ac->ares != NULL) {
166 ldb_set_errstring(ac->module->ldb,
167 "Invalid number of results while searching "
168 "for template objects");
169 ret = LDB_ERR_OPERATIONS_ERROR;
173 ac->ares = talloc_steal(ac, ares);
177 case LDB_REPLY_REFERRAL:
186 ret = samldb_next_step(ac);
191 if (ret != LDB_SUCCESS) {
192 return ldb_module_done(ac->req, NULL, NULL, ret);
198 static int samldb_search_template(struct samldb_ctx *ac)
200 struct event_context *ev;
201 struct loadparm_context *lparm_ctx;
202 struct ldb_context *templates_ldb;
203 char *templates_ldb_path;
204 struct ldb_request *req;
205 struct ldb_dn *basedn;
209 opaque = ldb_get_opaque(ac->module->ldb, "loadparm");
210 lparm_ctx = talloc_get_type(opaque, struct loadparm_context);
211 if (lparm_ctx == NULL) {
212 ldb_set_errstring(ac->module->ldb,
213 "Unable to find loadparm context\n");
214 return LDB_ERR_OPERATIONS_ERROR;
217 opaque = ldb_get_opaque(ac->module->ldb, "templates_ldb");
218 templates_ldb = talloc_get_type(opaque, struct ldb_context);
220 /* make sure we have the templates ldb */
221 if (!templates_ldb) {
222 templates_ldb_path = samdb_relative_path(ac->module->ldb, ac,
224 if (!templates_ldb_path) {
225 ldb_set_errstring(ac->module->ldb,
226 "samldb_init_template: ERROR: Failed "
227 "to contruct path for template db");
228 return LDB_ERR_OPERATIONS_ERROR;
231 ev = ldb_get_event_context(ac->module->ldb);
233 templates_ldb = ldb_wrap_connect(ac->module->ldb, ev,
234 lparm_ctx, templates_ldb_path,
235 NULL, NULL, 0, NULL);
236 talloc_free(templates_ldb_path);
238 if (!templates_ldb) {
239 return LDB_ERR_OPERATIONS_ERROR;
242 if (!talloc_reference(templates_ldb, ev)) {
243 return LDB_ERR_OPERATIONS_ERROR;
246 ret = ldb_set_opaque(ac->module->ldb,
247 "templates_ldb", templates_ldb);
248 if (ret != LDB_SUCCESS) {
253 /* search template */
254 basedn = ldb_dn_new_fmt(ac, templates_ldb,
255 "cn=Template%s,cn=Templates", ac->type);
256 if (basedn == NULL) {
257 ldb_set_errstring(ac->module->ldb,
258 "samldb_init_template: ERROR: Failed "
259 "to contruct DN for template");
260 return LDB_ERR_OPERATIONS_ERROR;
263 /* pull the template record */
264 ret = ldb_build_search_req(&req, templates_ldb, ac,
265 basedn, LDB_SCOPE_BASE,
266 "(distinguishedName=*)", NULL,
268 ac, samldb_search_template_callback,
270 if (ret != LDB_SUCCESS) {
274 talloc_steal(req, basedn);
277 return ldb_request(templates_ldb, req);
280 static int samldb_apply_template(struct samldb_ctx *ac)
282 struct ldb_message_element *el;
283 struct ldb_message *msg;
287 msg = ac->ares->message;
289 for (i = 0; i < msg->num_elements; i++) {
290 el = &msg->elements[i];
291 /* some elements should not be copied */
292 if (ldb_attr_cmp(el->name, "cn") == 0 ||
293 ldb_attr_cmp(el->name, "name") == 0 ||
294 ldb_attr_cmp(el->name, "objectClass") == 0 ||
295 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
296 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
297 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
298 ldb_attr_cmp(el->name, "objectGUID") == 0) {
301 for (j = 0; j < el->num_values; j++) {
302 ret = samdb_find_or_add_attribute(
303 ac->module->ldb, ac->msg, el->name,
304 (char *)el->values[j].data);
305 if (ret != LDB_SUCCESS) {
306 ldb_set_errstring(ac->module->ldb,
307 "Failed adding template attribute\n");
308 return LDB_ERR_OPERATIONS_ERROR;
313 return samldb_next_step(ac);
316 static int samldb_get_parent_domain(struct samldb_ctx *ac);
318 static int samldb_get_parent_domain_callback(struct ldb_request *req,
319 struct ldb_reply *ares)
321 struct samldb_ctx *ac;
325 ac = talloc_get_type(req->context, struct samldb_ctx);
328 ret = LDB_ERR_OPERATIONS_ERROR;
331 if (ares->error != LDB_SUCCESS) {
332 return ldb_module_done(ac->req, ares->controls,
333 ares->response, ares->error);
336 switch (ares->type) {
337 case LDB_REPLY_ENTRY:
339 if (ac->domain_dn != NULL) {
341 ldb_set_errstring(ac->module->ldb,
342 "Invalid number of results while searching "
343 "for domain object");
344 ret = LDB_ERR_OPERATIONS_ERROR;
348 nextRid = ldb_msg_find_attr_as_string(ares->message,
350 if (nextRid == NULL) {
351 ldb_asprintf_errstring(ac->module->ldb,
352 "while looking for domain above %s attribute nextRid not found in %s\n",
353 ldb_dn_get_linearized(ac->req->op.add.message->dn),
354 ldb_dn_get_linearized(ares->message->dn));
355 ret = LDB_ERR_OPERATIONS_ERROR;
359 ac->next_rid = strtol(nextRid, NULL, 0);
361 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
363 if (ac->domain_sid == NULL) {
364 ldb_set_errstring(ac->module->ldb,
365 "error retrieving parent domain domain sid!\n");
366 ret = LDB_ERR_CONSTRAINT_VIOLATION;
369 ac->domain_dn = talloc_steal(ac, ares->message->dn);
373 ldb_reset_err_string(ac->module->ldb);
376 case LDB_REPLY_REFERRAL:
385 if (ac->domain_dn == NULL) {
387 ret = samldb_get_parent_domain(ac);
390 ret = samldb_next_step(ac);
396 if (ret != LDB_SUCCESS) {
397 return ldb_module_done(ac->req, NULL, NULL, ret);
403 /* Find a domain object in the parents of a particular DN. */
404 static int samldb_get_parent_domain(struct samldb_ctx *ac)
406 static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
407 struct ldb_request *req;
411 if (ac->check_dn == NULL) {
412 return LDB_ERR_OPERATIONS_ERROR;
415 dn = ldb_dn_get_parent(ac, ac->check_dn);
417 ldb_set_errstring(ac->module->ldb,
418 "Unable to find parent domain object");
419 return LDB_ERR_CONSTRAINT_VIOLATION;
424 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
426 "(|(objectClass=domain)"
427 "(objectClass=builtinDomain)"
428 "(objectClass=samba4LocalDomain))",
431 ac, samldb_get_parent_domain_callback,
434 if (ret != LDB_SUCCESS) {
438 return ldb_next_request(ac->module, req);
441 static int samldb_generate_samAccountName(struct ldb_message *msg)
445 /* Format: $000000-000000000000 */
447 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
448 (unsigned int)generate_random(),
449 (unsigned int)generate_random(),
450 (unsigned int)generate_random());
452 return LDB_ERR_OPERATIONS_ERROR;
454 return ldb_msg_add_steal_string(msg, "samAccountName", name);
457 static int samldb_check_samAccountName_callback(struct ldb_request *req,
458 struct ldb_reply *ares)
460 struct samldb_ctx *ac;
463 ac = talloc_get_type(req->context, struct samldb_ctx);
466 ret = LDB_ERR_OPERATIONS_ERROR;
469 if (ares->error != LDB_SUCCESS) {
470 return ldb_module_done(ac->req, ares->controls,
471 ares->response, ares->error);
474 switch (ares->type) {
475 case LDB_REPLY_ENTRY:
477 /* if we get an entry it means this samAccountName
479 return ldb_module_done(ac->req, NULL, NULL,
480 LDB_ERR_ENTRY_ALREADY_EXISTS);
482 case LDB_REPLY_REFERRAL:
490 /* not found, go on */
492 ret = samldb_next_step(ac);
497 if (ret != LDB_SUCCESS) {
498 return ldb_module_done(ac->req, NULL, NULL, ret);
504 static int samldb_check_samAccountName(struct samldb_ctx *ac)
506 struct ldb_request *req;
511 if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
512 ret = samldb_generate_samAccountName(ac->msg);
513 if (ret != LDB_SUCCESS) {
518 name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
520 return LDB_ERR_OPERATIONS_ERROR;
522 filter = talloc_asprintf(ac, "samAccountName=%s", name);
523 if (filter == NULL) {
524 return LDB_ERR_OPERATIONS_ERROR;
527 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
528 ac->domain_dn, LDB_SCOPE_SUBTREE,
531 ac, samldb_check_samAccountName_callback,
534 if (ret != LDB_SUCCESS) {
538 return ldb_next_request(ac->module, req);
541 static int samldb_check_samAccountType(struct samldb_ctx *ac)
543 unsigned int account_type;
544 unsigned int group_type;
548 /* make sure sAMAccountType is not specified */
549 if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
550 ldb_asprintf_errstring(ac->module->ldb,
551 "sAMAccountType must not be specified");
552 return LDB_ERR_UNWILLING_TO_PERFORM;
555 if (strcmp("user", ac->type) == 0) {
556 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
558 ldb_asprintf_errstring(ac->module->ldb,
559 "userAccountControl invalid");
560 return LDB_ERR_UNWILLING_TO_PERFORM;
562 account_type = samdb_uf2atype(uac);
563 ret = samdb_msg_add_uint(ac->module->ldb,
567 if (ret != LDB_SUCCESS) {
572 if (strcmp("group", ac->type) == 0) {
574 group_type = samdb_result_uint(ac->msg, "groupType", 0);
575 if (group_type == 0) {
576 ldb_asprintf_errstring(ac->module->ldb,
577 "groupType invalid");
578 return LDB_ERR_UNWILLING_TO_PERFORM;
580 account_type = samdb_gtype2atype(group_type);
581 ret = samdb_msg_add_uint(ac->module->ldb,
585 if (ret != LDB_SUCCESS) {
591 return samldb_next_step(ac);
594 static int samldb_get_sid_domain_callback(struct ldb_request *req,
595 struct ldb_reply *ares)
597 struct samldb_ctx *ac;
601 ac = talloc_get_type(req->context, struct samldb_ctx);
604 ret = LDB_ERR_OPERATIONS_ERROR;
607 if (ares->error != LDB_SUCCESS) {
608 return ldb_module_done(ac->req, ares->controls,
609 ares->response, ares->error);
612 switch (ares->type) {
613 case LDB_REPLY_ENTRY:
615 if (ac->next_rid != 0) {
617 ldb_set_errstring(ac->module->ldb,
618 "Invalid number of results while searching "
619 "for domain object");
620 ret = LDB_ERR_OPERATIONS_ERROR;
624 nextRid = ldb_msg_find_attr_as_string(ares->message,
626 if (nextRid == NULL) {
627 ldb_asprintf_errstring(ac->module->ldb,
628 "attribute nextRid not found in %s\n",
629 ldb_dn_get_linearized(ares->message->dn));
630 ret = LDB_ERR_OPERATIONS_ERROR;
634 ac->next_rid = strtol(nextRid, NULL, 0);
636 ac->domain_dn = talloc_steal(ac, ares->message->dn);
642 case LDB_REPLY_REFERRAL:
650 if (ac->next_rid == 0) {
651 ldb_asprintf_errstring(ac->module->ldb,
652 "Unable to get nextRid from domain entry\n");
653 ret = LDB_ERR_OPERATIONS_ERROR;
658 ret = samldb_next_step(ac);
663 if (ret != LDB_SUCCESS) {
664 return ldb_module_done(ac->req, NULL, NULL, ret);
670 /* Find a domain object in the parents of a particular DN. */
671 static int samldb_get_sid_domain(struct samldb_ctx *ac)
673 static const char * const attrs[2] = { "nextRid", NULL };
674 struct ldb_request *req;
678 if (ac->sid == NULL) {
679 return LDB_ERR_OPERATIONS_ERROR;
682 ac->domain_sid = dom_sid_dup(ac, ac->sid);
683 if (!ac->domain_sid) {
684 return LDB_ERR_OPERATIONS_ERROR;
686 /* get the domain component part of the provided SID */
687 ac->domain_sid->num_auths--;
689 filter = talloc_asprintf(ac, "(&(objectSid=%s)"
690 "(|(objectClass=domain)"
691 "(objectClass=builtinDomain)"
692 "(objectClass=samba4LocalDomain)))",
693 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
694 if (filter == NULL) {
695 return LDB_ERR_OPERATIONS_ERROR;
698 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
699 ldb_get_default_basedn(ac->module->ldb),
703 ac, samldb_get_sid_domain_callback,
706 if (ret != LDB_SUCCESS) {
711 return ldb_next_request(ac->module, req);
714 static bool samldb_msg_add_sid(struct ldb_message *msg,
716 const struct dom_sid *sid)
719 enum ndr_err_code ndr_err;
721 ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
722 (ndr_push_flags_fn_t)ndr_push_dom_sid);
723 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
726 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
729 static int samldb_new_sid(struct samldb_ctx *ac)
732 if (ac->domain_sid == NULL || ac->next_rid == 0) {
733 return LDB_ERR_OPERATIONS_ERROR;
736 ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
737 if (ac->sid == NULL) {
738 return LDB_ERR_OPERATIONS_ERROR;
741 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
742 return LDB_ERR_OPERATIONS_ERROR;
745 return samldb_next_step(ac);
748 static int samldb_check_sid_callback(struct ldb_request *req,
749 struct ldb_reply *ares)
751 struct samldb_ctx *ac;
754 ac = talloc_get_type(req->context, struct samldb_ctx);
757 ret = LDB_ERR_OPERATIONS_ERROR;
760 if (ares->error != LDB_SUCCESS) {
761 return ldb_module_done(ac->req, ares->controls,
762 ares->response, ares->error);
765 switch (ares->type) {
766 case LDB_REPLY_ENTRY:
768 /* if we get an entry it means an object with the
769 * requested sid exists */
770 return ldb_module_done(ac->req, NULL, NULL,
771 LDB_ERR_CONSTRAINT_VIOLATION);
773 case LDB_REPLY_REFERRAL:
780 /* not found, go on */
782 ret = samldb_next_step(ac);
787 if (ret != LDB_SUCCESS) {
788 return ldb_module_done(ac->req, NULL, NULL, ret);
794 static int samldb_check_sid(struct samldb_ctx *ac)
796 const char *const attrs[2] = { "objectSid", NULL };
797 struct ldb_request *req;
801 if (ac->sid == NULL) {
802 return LDB_ERR_OPERATIONS_ERROR;
805 filter = talloc_asprintf(ac, "(objectSid=%s)",
806 ldap_encode_ndr_dom_sid(ac, ac->sid));
807 if (filter == NULL) {
808 return LDB_ERR_OPERATIONS_ERROR;
811 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
812 ldb_get_default_basedn(ac->module->ldb),
816 ac, samldb_check_sid_callback,
819 if (ret != LDB_SUCCESS) {
823 return ldb_next_request(ac->module, req);
826 static int samldb_notice_sid_callback(struct ldb_request *req,
827 struct ldb_reply *ares)
829 struct samldb_ctx *ac;
832 ac = talloc_get_type(req->context, struct samldb_ctx);
835 ret = LDB_ERR_OPERATIONS_ERROR;
838 if (ares->error != LDB_SUCCESS) {
839 return ldb_module_done(ac->req, ares->controls,
840 ares->response, ares->error);
842 if (ares->type != LDB_REPLY_DONE) {
843 ldb_set_errstring(ac->module->ldb,
844 "Invalid reply type!\n");
845 ret = LDB_ERR_OPERATIONS_ERROR;
849 ret = samldb_next_step(ac);
852 if (ret != LDB_SUCCESS) {
853 return ldb_module_done(ac->req, NULL, NULL, ret);
859 /* If we are adding new users/groups, we need to update the nextRid
860 * attribute to be 'above' the new/incoming RID. Attempt to do it
862 static int samldb_notice_sid(struct samldb_ctx *ac)
864 uint32_t old_id, new_id;
865 struct ldb_request *req;
866 struct ldb_message *msg;
867 struct ldb_message_element *els;
868 struct ldb_val *vals;
871 old_id = ac->next_rid;
872 new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
874 if (old_id >= new_id) {
875 /* no need to update the domain nextRid attribute */
876 return samldb_next_step(ac);
879 /* we do a delete and add as a single operation. That prevents
880 a race, in case we are not actually on a transaction db */
881 msg = talloc_zero(ac, struct ldb_message);
883 ldb_oom(ac->module->ldb);
884 return LDB_ERR_OPERATIONS_ERROR;
886 els = talloc_array(msg, struct ldb_message_element, 2);
888 ldb_oom(ac->module->ldb);
889 return LDB_ERR_OPERATIONS_ERROR;
891 vals = talloc_array(msg, struct ldb_val, 2);
893 ldb_oom(ac->module->ldb);
894 return LDB_ERR_OPERATIONS_ERROR;
896 msg->dn = ac->domain_dn;
897 msg->num_elements = 2;
900 els[0].num_values = 1;
901 els[0].values = &vals[0];
902 els[0].flags = LDB_FLAG_MOD_DELETE;
903 els[0].name = talloc_strdup(msg, "nextRid");
905 ldb_oom(ac->module->ldb);
906 return LDB_ERR_OPERATIONS_ERROR;
909 els[1].num_values = 1;
910 els[1].values = &vals[1];
911 els[1].flags = LDB_FLAG_MOD_ADD;
912 els[1].name = els[0].name;
914 vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
916 ldb_oom(ac->module->ldb);
917 return LDB_ERR_OPERATIONS_ERROR;
919 vals[0].length = strlen((char *)vals[0].data);
921 vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
923 ldb_oom(ac->module->ldb);
924 return LDB_ERR_OPERATIONS_ERROR;
926 vals[1].length = strlen((char *)vals[1].data);
928 ret = ldb_build_mod_req(&req, ac->module->ldb, ac,
930 ac, samldb_notice_sid_callback,
932 if (ret != LDB_SUCCESS) {
936 return ldb_next_request(ac->module, req);
939 static int samldb_add_entry_callback(struct ldb_request *req,
940 struct ldb_reply *ares)
942 struct samldb_ctx *ac;
944 ac = talloc_get_type(req->context, struct samldb_ctx);
947 return ldb_module_done(ac->req, NULL, NULL,
948 LDB_ERR_OPERATIONS_ERROR);
950 if (ares->error != LDB_SUCCESS) {
951 return ldb_module_done(ac->req, ares->controls,
952 ares->response, ares->error);
954 if (ares->type != LDB_REPLY_DONE) {
955 ldb_set_errstring(ac->module->ldb,
956 "Invalid reply type!\n");
957 return ldb_module_done(ac->req, NULL, NULL,
958 LDB_ERR_OPERATIONS_ERROR);
961 /* we exit the samldb module here */
962 return ldb_module_done(ac->req, ares->controls,
963 ares->response, LDB_SUCCESS);
966 static int samldb_add_entry(struct samldb_ctx *ac)
968 struct ldb_request *req;
971 ret = ldb_build_add_req(&req, ac->module->ldb, ac,
974 ac, samldb_add_entry_callback,
976 if (ret != LDB_SUCCESS) {
980 return ldb_next_request(ac->module, req);
983 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
987 /* first look for the template */
989 ret = samldb_add_step(ac, samldb_search_template);
990 if (ret != LDB_SUCCESS) return ret;
993 ret = samldb_add_step(ac, samldb_apply_template);
994 if (ret != LDB_SUCCESS) return ret;
996 /* search for a parent domain objet */
997 ac->check_dn = ac->req->op.add.message->dn;
998 ret = samldb_add_step(ac, samldb_get_parent_domain);
999 if (ret != LDB_SUCCESS) return ret;
1001 /* check if we have a valid samAccountName */
1002 ret = samldb_add_step(ac, samldb_check_samAccountName);
1003 if (ret != LDB_SUCCESS) return ret;
1005 /* check account_type/group_type */
1006 ret = samldb_add_step(ac, samldb_check_samAccountType);
1007 if (ret != LDB_SUCCESS) return ret;
1009 /* check if we have a valid SID */
1010 ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1012 ret = samldb_add_step(ac, samldb_new_sid);
1013 if (ret != LDB_SUCCESS) return ret;
1015 ret = samldb_add_step(ac, samldb_get_sid_domain);
1016 if (ret != LDB_SUCCESS) return ret;
1019 ret = samldb_add_step(ac, samldb_check_sid);
1020 if (ret != LDB_SUCCESS) return ret;
1022 ret = samldb_add_step(ac, samldb_notice_sid);
1023 if (ret != LDB_SUCCESS) return ret;
1025 /* finally proceed with adding the entry */
1026 ret = samldb_add_step(ac, samldb_add_entry);
1027 if (ret != LDB_SUCCESS) return ret;
1029 return samldb_first_step(ac);
1031 /* TODO: userAccountControl, badPwdCount, codePage,
1032 * countryCode, badPasswordTime, lastLogoff, lastLogon,
1033 * pwdLastSet, primaryGroupID, accountExpires, logonCount */
1037 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
1038 struct ldb_reply *ares)
1040 struct samldb_ctx *ac;
1041 const char *nextRid;
1045 ac = talloc_get_type(req->context, struct samldb_ctx);
1048 ret = LDB_ERR_OPERATIONS_ERROR;
1051 if (ares->error != LDB_SUCCESS) {
1052 return ldb_module_done(ac->req, ares->controls,
1053 ares->response, ares->error);
1056 switch (ares->type) {
1057 case LDB_REPLY_ENTRY:
1059 if (ac->next_rid != 0) {
1061 ldb_set_errstring(ac->module->ldb,
1062 "Invalid number of results while searching "
1063 "for domain object");
1064 ret = LDB_ERR_OPERATIONS_ERROR;
1068 nextRid = ldb_msg_find_attr_as_string(ares->message,
1070 if (nextRid == NULL) {
1071 ldb_asprintf_errstring(ac->module->ldb,
1072 "while looking for forign sid %s attribute nextRid not found in %s\n",
1073 dom_sid_string(ares, ac->sid), ldb_dn_get_linearized(ares->message->dn));
1074 ret = LDB_ERR_OPERATIONS_ERROR;
1078 ac->next_rid = strtol(nextRid, NULL, 0);
1080 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1082 name = samdb_result_string(ares->message, "name", NULL);
1083 ldb_debug(ac->module->ldb, LDB_DEBUG_TRACE,
1084 "NOTE (strange but valid): Adding foreign SID "
1085 "record with SID %s, but this domain (%s) is "
1086 "not foreign in the database",
1087 dom_sid_string(ares, ac->sid), name);
1092 case LDB_REPLY_REFERRAL:
1097 case LDB_REPLY_DONE:
1099 /* if this is a fake foreign SID, notice the SID */
1100 if (ac->domain_dn) {
1101 ret = samldb_notice_sid(ac);
1106 ret = samldb_next_step(ac);
1111 if (ret != LDB_SUCCESS) {
1112 return ldb_module_done(ac->req, NULL, NULL, ret);
1118 /* Find a domain object in the parents of a particular DN. */
1119 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1121 static const char * const attrs[3] = { "nextRid", "name", NULL };
1122 struct ldb_request *req;
1127 if (ac->sid == NULL) {
1128 return LDB_ERR_OPERATIONS_ERROR;
1131 status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL);
1132 if (!NT_STATUS_IS_OK(status)) {
1133 return LDB_ERR_OPERATIONS_ERROR;
1136 filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1137 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1138 if (filter == NULL) {
1139 return LDB_ERR_OPERATIONS_ERROR;
1142 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
1143 ldb_get_default_basedn(ac->module->ldb),
1147 ac, samldb_foreign_notice_sid_callback,
1150 if (ret != LDB_SUCCESS) {
1155 return ldb_next_request(ac->module, req);
1158 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1162 ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1163 if (ac->sid == NULL) {
1164 ac->sid = dom_sid_parse_talloc(ac->msg,
1165 (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1167 ldb_set_errstring(ac->module->ldb,
1168 "No valid found SID in "
1169 "ForeignSecurityPrincipal CN!");
1171 return LDB_ERR_CONSTRAINT_VIOLATION;
1173 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1175 return LDB_ERR_OPERATIONS_ERROR;
1179 /* first look for the template */
1180 ac->type = "foreignSecurityPrincipal";
1181 ret = samldb_add_step(ac, samldb_search_template);
1182 if (ret != LDB_SUCCESS) return ret;
1185 ret = samldb_add_step(ac, samldb_apply_template);
1186 if (ret != LDB_SUCCESS) return ret;
1188 /* check we do not already have this SID */
1189 ret = samldb_add_step(ac, samldb_check_sid);
1190 if (ret != LDB_SUCCESS) return ret;
1192 /* check if we need to notice this SID */
1193 ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1194 if (ret != LDB_SUCCESS) return ret;
1196 /* finally proceed with adding the entry */
1197 ret = samldb_add_step(ac, samldb_add_entry);
1198 if (ret != LDB_SUCCESS) return ret;
1200 return samldb_first_step(ac);
1203 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1205 const char *rdn_name;
1207 rdn_name = ldb_dn_get_rdn_name(dn);
1209 if (strcasecmp(rdn_name, "cn") != 0) {
1210 ldb_asprintf_errstring(module->ldb,
1211 "Bad RDN (%s=) for samldb object, "
1212 "should be CN=!\n", rdn_name);
1213 return LDB_ERR_CONSTRAINT_VIOLATION;
1220 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1222 struct samldb_ctx *ac;
1225 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1227 /* do not manipulate our control entries */
1228 if (ldb_dn_is_special(req->op.add.message->dn)) {
1229 return ldb_next_request(module, req);
1232 ac = samldb_ctx_init(module, req);
1234 return LDB_ERR_OPERATIONS_ERROR;
1237 /* build the new msg */
1238 ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1241 ldb_debug(ac->module->ldb, LDB_DEBUG_FATAL,
1242 "samldb_add: ldb_msg_copy failed!\n");
1243 return LDB_ERR_OPERATIONS_ERROR;
1246 if (samdb_find_attribute(module->ldb, ac->msg,
1247 "objectclass", "computer") != NULL) {
1249 /* make sure the computer object also has the 'user'
1250 * objectclass so it will be handled by the next call */
1251 ret = samdb_find_or_add_value(module->ldb, ac->msg,
1252 "objectclass", "user");
1253 if (ret != LDB_SUCCESS) {
1259 if (samdb_find_attribute(module->ldb, ac->msg,
1260 "objectclass", "user") != NULL) {
1262 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1263 if (ret != LDB_SUCCESS) {
1268 return samldb_fill_object(ac, "user");
1271 if (samdb_find_attribute(module->ldb, ac->msg,
1272 "objectclass", "group") != NULL) {
1274 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1275 if (ret != LDB_SUCCESS) {
1280 return samldb_fill_object(ac, "group");
1283 /* perhaps a foreignSecurityPrincipal? */
1284 if (samdb_find_attribute(module->ldb, ac->msg,
1286 "foreignSecurityPrincipal") != NULL) {
1288 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1289 if (ret != LDB_SUCCESS) {
1294 return samldb_fill_foreignSecurityPrincipal_object(ac);
1299 /* nothing matched, go on */
1300 return ldb_next_request(module, req);
1304 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1306 struct ldb_message *msg;
1307 struct ldb_message_element *el, *el2;
1309 unsigned int group_type, user_account_control, account_type;
1310 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1311 return ldb_next_request(module, req);
1314 if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1315 ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified");
1316 return LDB_ERR_UNWILLING_TO_PERFORM;
1319 /* TODO: do not modify original request, create a new one */
1321 el = ldb_msg_find_element(req->op.mod.message, "groupType");
1322 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1323 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1325 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1326 account_type = samdb_gtype2atype(group_type);
1327 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1330 if (ret != LDB_SUCCESS) {
1333 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1334 el2->flags = LDB_FLAG_MOD_REPLACE;
1337 el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1338 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1339 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1341 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1342 account_type = samdb_uf2atype(user_account_control);
1343 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1346 if (ret != LDB_SUCCESS) {
1349 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1350 el2->flags = LDB_FLAG_MOD_REPLACE;
1352 return ldb_next_request(module, req);
1356 static int samldb_init(struct ldb_module *module)
1358 return ldb_next_init(module);
1361 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1363 .init_context = samldb_init,
1365 .modify = samldb_modify