4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Nadezhda Ivanova 2009
6 Copyright (C) Anatoliy Atanasov 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: ldb ACL module
27 * Description: Module that performs authorisation access checks based on the
28 * account's security context and the DACL of the object being polled.
29 * Only DACL checks implemented at this point
31 * Authors: Nadezhda Ivanova, Anatoliy Atanasov
35 #include "ldb_module.h"
36 #include "auth/auth.h"
37 #include "libcli/security/security.h"
38 #include "dsdb/samdb/samdb.h"
39 #include "librpc/gen_ndr/ndr_security.h"
40 #include "param/param.h"
41 #include "dsdb/samdb/ldb_modules/util.h"
42 #include "lib/util/tsort.h"
43 #include "system/kerberos.h"
44 #include "auth/kerberos/kerberos.h"
51 const char **password_attrs;
52 void *cached_schema_ptr;
53 uint64_t cached_schema_metadata_usn;
54 uint64_t cached_schema_loaded_usn;
55 const char **confidential_attrs;
59 struct ldb_module *module;
60 struct ldb_request *req;
62 bool am_administrator;
63 bool constructed_attrs;
64 bool allowedAttributes;
65 bool allowedAttributesEffective;
66 bool allowedChildClasses;
67 bool allowedChildClassesEffective;
68 bool sDRightsEffective;
69 struct dsdb_schema *schema;
72 static int acl_module_init(struct ldb_module *module)
74 struct ldb_context *ldb;
75 struct acl_private *data;
78 ldb = ldb_module_get_ctx(module);
80 data = talloc_zero(module, struct acl_private);
85 data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
86 NULL, "acl", "search", true);
87 ldb_module_set_private(module, data);
89 ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
90 if (ret != LDB_SUCCESS) {
91 ldb_debug(ldb, LDB_DEBUG_ERROR,
92 "acl_module_init: Unable to register control with rootdse!\n");
93 return ldb_operr(ldb);
96 return ldb_next_init(module);
99 static int acl_allowedAttributes(struct ldb_module *module,
100 const struct dsdb_schema *schema,
101 struct ldb_message *sd_msg,
102 struct ldb_message *msg,
103 struct acl_context *ac)
105 struct ldb_message_element *oc_el;
106 struct ldb_context *ldb = ldb_module_get_ctx(module);
108 const char **attr_list;
110 const struct dsdb_class *objectclass;
112 /* If we don't have a schema yet, we can't do anything... */
113 if (schema == NULL) {
114 ldb_asprintf_errstring(ldb, "cannot add allowedAttributes to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
115 return LDB_ERR_OPERATIONS_ERROR;
118 /* Must remove any existing attribute */
119 if (ac->allowedAttributes) {
120 ldb_msg_remove_attr(msg, "allowedAttributes");
123 mem_ctx = talloc_new(msg);
128 oc_el = ldb_msg_find_element(sd_msg, "objectClass");
129 attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
131 ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
132 talloc_free(mem_ctx);
133 return LDB_ERR_OPERATIONS_ERROR;
137 * Get the top-most structural object class for the ACL check
139 objectclass = dsdb_get_last_structural_class(ac->schema,
141 if (objectclass == NULL) {
142 ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s",
143 ldb_dn_get_linearized(sd_msg->dn));
144 talloc_free(mem_ctx);
145 return LDB_ERR_OPERATIONS_ERROR;
148 if (ac->allowedAttributes) {
149 for (i=0; attr_list && attr_list[i]; i++) {
150 ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
153 if (ac->allowedAttributesEffective) {
154 struct security_descriptor *sd;
155 struct dom_sid *sid = NULL;
156 struct ldb_control *as_system = ldb_request_get_control(ac->req,
157 LDB_CONTROL_AS_SYSTEM_OID);
159 if (as_system != NULL) {
160 as_system->critical = 0;
163 ldb_msg_remove_attr(msg, "allowedAttributesEffective");
164 if (ac->am_system || as_system) {
165 for (i=0; attr_list && attr_list[i]; i++) {
166 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
171 ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), mem_ctx, sd_msg, &sd);
173 if (ret != LDB_SUCCESS) {
177 sid = samdb_result_dom_sid(mem_ctx, sd_msg, "objectSid");
178 for (i=0; attr_list && attr_list[i]; i++) {
179 const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
182 return ldb_operr(ldb);
184 /* remove constructed attributes */
185 if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
187 || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
190 ret = acl_check_access_on_attribute(module,
197 if (ret == LDB_SUCCESS) {
198 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
205 static int acl_childClasses(struct ldb_module *module,
206 const struct dsdb_schema *schema,
207 struct ldb_message *sd_msg,
208 struct ldb_message *msg,
209 const char *attrName)
211 struct ldb_message_element *oc_el;
212 struct ldb_message_element *allowedClasses;
213 const struct dsdb_class *sclass;
217 /* If we don't have a schema yet, we can't do anything... */
218 if (schema == NULL) {
219 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add childClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
220 return LDB_ERR_OPERATIONS_ERROR;
223 /* Must remove any existing attribute, or else confusion reigns */
224 ldb_msg_remove_attr(msg, attrName);
225 ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
226 if (ret != LDB_SUCCESS) {
230 oc_el = ldb_msg_find_element(sd_msg, "objectClass");
232 for (i=0; oc_el && i < oc_el->num_values; i++) {
233 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
235 /* We don't know this class? what is going on? */
239 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
240 ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
243 if (allowedClasses->num_values > 1) {
244 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
245 for (i=1 ; i < allowedClasses->num_values; i++) {
246 struct ldb_val *val1 = &allowedClasses->values[i-1];
247 struct ldb_val *val2 = &allowedClasses->values[i];
248 if (data_blob_cmp(val1, val2) == 0) {
249 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
250 allowedClasses->num_values--;
259 static int acl_childClassesEffective(struct ldb_module *module,
260 const struct dsdb_schema *schema,
261 struct ldb_message *sd_msg,
262 struct ldb_message *msg,
263 struct acl_context *ac)
265 struct ldb_message_element *oc_el;
266 struct ldb_message_element *allowedClasses = NULL;
267 const struct dsdb_class *sclass;
268 struct security_descriptor *sd;
269 struct ldb_control *as_system = ldb_request_get_control(ac->req,
270 LDB_CONTROL_AS_SYSTEM_OID);
271 struct dom_sid *sid = NULL;
275 if (as_system != NULL) {
276 as_system->critical = 0;
279 if (ac->am_system || as_system) {
280 return acl_childClasses(module, schema, sd_msg, msg, "allowedChildClassesEffective");
283 /* If we don't have a schema yet, we can't do anything... */
284 if (schema == NULL) {
285 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add allowedChildClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
286 return LDB_ERR_OPERATIONS_ERROR;
289 /* Must remove any existing attribute, or else confusion reigns */
290 ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
292 oc_el = ldb_msg_find_element(sd_msg, "objectClass");
293 ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
294 if (ret != LDB_SUCCESS) {
298 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
299 for (i=0; oc_el && i < oc_el->num_values; i++) {
300 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
302 /* We don't know this class? what is going on? */
306 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
307 const struct dsdb_class *sc;
309 sc = dsdb_class_by_lDAPDisplayName(schema,
310 sclass->possibleInferiors[j]);
312 /* We don't know this class? what is going on? */
316 ret = acl_check_access_on_objectclass(module, ac,
318 SEC_ADS_CREATE_CHILD,
320 if (ret == LDB_SUCCESS) {
321 ldb_msg_add_string(msg, "allowedChildClassesEffective",
322 sclass->possibleInferiors[j]);
326 allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
327 if (!allowedClasses) {
331 if (allowedClasses->num_values > 1) {
332 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
333 for (i=1 ; i < allowedClasses->num_values; i++) {
334 struct ldb_val *val1 = &allowedClasses->values[i-1];
335 struct ldb_val *val2 = &allowedClasses->values[i];
336 if (data_blob_cmp(val1, val2) == 0) {
337 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
338 allowedClasses->num_values--;
346 static int acl_sDRightsEffective(struct ldb_module *module,
347 struct ldb_message *sd_msg,
348 struct ldb_message *msg,
349 struct acl_context *ac)
351 struct ldb_context *ldb = ldb_module_get_ctx(module);
352 struct ldb_message_element *rightsEffective;
354 struct security_descriptor *sd;
355 struct ldb_control *as_system = ldb_request_get_control(ac->req,
356 LDB_CONTROL_AS_SYSTEM_OID);
357 struct dom_sid *sid = NULL;
360 if (as_system != NULL) {
361 as_system->critical = 0;
364 /* Must remove any existing attribute, or else confusion reigns */
365 ldb_msg_remove_attr(msg, "sDRightsEffective");
366 ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
367 if (ret != LDB_SUCCESS) {
370 if (ac->am_system || as_system) {
371 flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL;
373 const struct dsdb_class *objectclass;
374 const struct dsdb_attribute *attr;
376 objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
377 if (objectclass == NULL) {
378 return ldb_operr(ldb);
381 attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
382 "nTSecurityDescriptor");
384 return ldb_operr(ldb);
387 /* Get the security descriptor from the message */
388 ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
389 if (ret != LDB_SUCCESS) {
392 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
393 ret = acl_check_access_on_attribute(module,
400 if (ret == LDB_SUCCESS) {
401 flags |= SECINFO_OWNER | SECINFO_GROUP;
405 * This call is made with
406 * IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS
407 * and without reference to the dSHeuristics via
408 * dsdb_block_owner_implicit_rights(). This is
409 * probably a Windows bug but for now we match
412 ret = acl_check_access_on_attribute_implicit_owner(
420 IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
421 if (ret == LDB_SUCCESS) {
422 flags |= SECINFO_DACL;
424 ret = acl_check_access_on_attribute(module,
428 SEC_FLAG_SYSTEM_SECURITY,
431 if (ret == LDB_SUCCESS) {
432 flags |= SECINFO_SACL;
436 if (flags != (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_SACL)) {
437 const struct ldb_message_element *el = samdb_find_attribute(ldb,
446 return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
447 "sDRightsEffective", flags);
450 static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
451 struct ldb_context *ldb,
452 const struct ldb_val *spn_value,
453 uint32_t userAccountControl,
454 const struct ldb_val *samAccountName,
455 const struct ldb_val *dnsHostName,
456 const char *netbios_name,
457 const char *ntds_guid)
459 krb5_error_code ret, princ_size;
460 krb5_context krb_ctx;
461 krb5_error_code kerr;
462 krb5_principal principal;
463 char *instanceName = NULL;
464 char *serviceType = NULL;
465 char *serviceName = NULL;
466 const char *spn_value_str = NULL;
467 size_t account_name_len;
468 const char *forest_name = samdb_forest_name(ldb, mem_ctx);
469 const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
470 struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
471 struct loadparm_context);
472 bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
473 (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
475 spn_value_str = talloc_strndup(mem_ctx,
476 (const char *)spn_value->data,
478 if (spn_value_str == NULL) {
482 if (spn_value->length == samAccountName->length &&
483 strncasecmp((const char *)spn_value->data,
484 (const char *)samAccountName->data,
485 spn_value->length) == 0)
487 /* MacOS X sets this value, and setting an SPN of your
488 * own samAccountName is both pointless and safe */
492 kerr = smb_krb5_init_context_basic(mem_ctx,
496 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
497 "Could not initialize kerberos context.");
500 ret = krb5_parse_name(krb_ctx, spn_value_str, &principal);
502 krb5_free_context(krb_ctx);
503 return LDB_ERR_CONSTRAINT_VIOLATION;
506 princ_size = krb5_princ_size(krb_ctx, principal);
507 if (princ_size < 2) {
508 DBG_WARNING("princ_size=%d\n", princ_size);
512 ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
513 principal, 1, &instanceName);
517 ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
518 principal, 0, &serviceType);
522 if (krb5_princ_size(krb_ctx, principal) == 3) {
523 ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
524 principal, 2, &serviceName);
532 DBG_WARNING("is_dc=false, serviceName=%s,"
533 "serviceType=%s\n", serviceName,
537 if (strcasecmp(serviceType, "ldap") == 0) {
538 if (strcasecmp(serviceName, netbios_name) != 0 &&
539 strcasecmp(serviceName, forest_name) != 0) {
540 DBG_WARNING("serviceName=%s\n", serviceName);
544 } else if (strcasecmp(serviceType, "gc") == 0) {
545 if (strcasecmp(serviceName, forest_name) != 0) {
546 DBG_WARNING("serviceName=%s\n", serviceName);
550 if (strcasecmp(serviceName, base_domain) != 0 &&
551 strcasecmp(serviceName, netbios_name) != 0) {
552 DBG_WARNING("serviceType=%s, "
554 serviceType, serviceName);
560 account_name_len = samAccountName->length;
561 if (account_name_len &&
562 samAccountName->data[account_name_len - 1] == '$')
564 /* Account for the '$' character. */
568 /* instanceName can be samAccountName without $ or dnsHostName
569 * or "ntds_guid._msdcs.forest_domain for DC objects */
570 if (strlen(instanceName) == account_name_len
571 && strncasecmp(instanceName,
572 (const char *)samAccountName->data,
573 account_name_len) == 0)
577 if ((dnsHostName != NULL) &&
578 strlen(instanceName) == dnsHostName->length &&
579 (strncasecmp(instanceName,
580 (const char *)dnsHostName->data,
581 dnsHostName->length) == 0))
586 const char *guid_str = NULL;
587 guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
590 if (strcasecmp(instanceName, guid_str) == 0) {
596 krb5_free_principal(krb_ctx, principal);
597 krb5_free_context(krb_ctx);
598 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
599 "acl: spn validation failed for "
600 "spn[%.*s] uac[0x%x] account[%.*s] hostname[%.*s] "
601 "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
602 (int)spn_value->length, spn_value->data,
603 (unsigned)userAccountControl,
604 (int)samAccountName->length, samAccountName->data,
605 dnsHostName != NULL ? (int)dnsHostName->length : 0,
606 dnsHostName != NULL ? (const char *)dnsHostName->data : "",
607 netbios_name, ntds_guid,
608 forest_name, base_domain);
609 return LDB_ERR_CONSTRAINT_VIOLATION;
612 krb5_free_principal(krb_ctx, principal);
613 krb5_free_context(krb_ctx);
618 * Passing in 'el' is critical, we want to check all the values.
621 static int acl_check_spn(TALLOC_CTX *mem_ctx,
622 struct ldb_module *module,
623 struct ldb_request *req,
624 const struct ldb_message_element *el,
625 struct security_descriptor *sd,
627 const struct dsdb_attribute *attr,
628 const struct dsdb_class *objectclass,
629 const struct ldb_control *implicit_validated_write_control)
633 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
634 struct ldb_context *ldb = ldb_module_get_ctx(module);
635 struct ldb_result *acl_res;
636 struct ldb_result *netbios_res;
637 struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
638 uint32_t userAccountControl;
639 const char *netbios_name;
640 const struct ldb_val *dns_host_name_val = NULL;
641 const struct ldb_val *sam_account_name_val = NULL;
643 char *ntds_guid = NULL;
644 const struct ldb_message *msg = NULL;
645 const struct ldb_message *search_res = NULL;
647 static const char *acl_attrs[] = {
650 "userAccountControl",
653 static const char *netbios_attrs[] = {
658 if (req->operation == LDB_MODIFY) {
659 msg = req->op.mod.message;
660 } else if (req->operation == LDB_ADD) {
661 msg = req->op.add.message;
664 if (implicit_validated_write_control != NULL) {
666 * The validated write control dispenses with ACL
667 * checks. We act as if we have an implicit Self Write
668 * privilege, but, assuming we don't have Write
669 * Property, still proceed with further validation
673 /* if we have wp, we can do whatever we like */
674 if (acl_check_access_on_attribute(module,
679 attr, objectclass) == LDB_SUCCESS) {
680 talloc_free(tmp_ctx);
684 ret = acl_check_extended_right(tmp_ctx,
689 acl_user_token(module),
690 GUID_DRS_VALIDATE_SPN,
694 if (ret != LDB_SUCCESS) {
695 dsdb_acl_debug(sd, acl_user_token(module),
699 talloc_free(tmp_ctx);
705 * If we have "validated write spn", allow delete of any
706 * existing value (this keeps constrained delete to the same
707 * rules as unconstrained)
709 if (req->operation == LDB_MODIFY) {
711 * If not add or replace (eg delete),
714 if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
715 LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
717 talloc_free(tmp_ctx);
721 ret = dsdb_module_search_dn(module, tmp_ctx,
724 DSDB_FLAG_NEXT_MODULE |
725 DSDB_FLAG_AS_SYSTEM |
726 DSDB_SEARCH_SHOW_RECYCLED,
728 if (ret != LDB_SUCCESS) {
729 talloc_free(tmp_ctx);
733 search_res = acl_res->msgs[0];
734 } else if (req->operation == LDB_ADD) {
737 talloc_free(tmp_ctx);
738 return LDB_ERR_OPERATIONS_ERROR;
741 if (req->operation == LDB_MODIFY) {
742 dns_host_name_val = ldb_msg_find_ldb_val(search_res, "dNSHostName");
745 ret = dsdb_msg_get_single_value(msg,
750 if (ret != LDB_SUCCESS) {
751 talloc_free(tmp_ctx);
755 userAccountControl = ldb_msg_find_attr_as_uint(search_res, "userAccountControl", 0);
757 if (req->operation == LDB_MODIFY) {
758 sam_account_name_val = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
761 ret = dsdb_msg_get_single_value(msg,
763 sam_account_name_val,
764 &sam_account_name_val,
766 if (ret != LDB_SUCCESS) {
767 talloc_free(tmp_ctx);
771 ret = dsdb_module_search(module, tmp_ctx,
772 &netbios_res, partitions_dn,
775 DSDB_FLAG_NEXT_MODULE |
779 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
781 netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
784 * NTDSDSA objectGuid of object we are checking SPN for
786 * Note - do we have the necessary attributes for this during an add operation?
787 * How should we test this?
789 if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
790 ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
791 msg->dn, &ntds, req);
792 if (ret != LDB_SUCCESS) {
793 ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
794 ldb_dn_get_linearized(msg->dn),
796 talloc_free(tmp_ctx);
797 return LDB_ERR_OPERATIONS_ERROR;
799 ntds_guid = GUID_string(tmp_ctx, &ntds);
802 for (i=0; i < el->num_values; i++) {
803 ret = acl_validate_spn_value(tmp_ctx,
807 sam_account_name_val,
811 if (ret != LDB_SUCCESS) {
812 talloc_free(tmp_ctx);
816 talloc_free(tmp_ctx);
820 static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
821 struct ldb_module *module,
822 struct ldb_request *req,
823 const struct ldb_message_element *el,
824 struct security_descriptor *sd,
826 const struct dsdb_attribute *attr,
827 const struct dsdb_class *objectclass,
828 const struct ldb_control *implicit_validated_write_control)
832 TALLOC_CTX *tmp_ctx = NULL;
833 struct ldb_context *ldb = ldb_module_get_ctx(module);
834 const struct dsdb_schema *schema = NULL;
835 const struct ldb_message_element *allowed_suffixes = NULL;
836 struct ldb_result *nc_res = NULL;
837 struct ldb_dn *nc_root = NULL;
838 const char *nc_dns_name = NULL;
839 const char *dnsHostName_str = NULL;
840 size_t dns_host_name_len;
841 size_t account_name_len;
842 const struct ldb_message *msg = NULL;
843 const struct ldb_message *search_res = NULL;
844 const struct ldb_val *samAccountName = NULL;
845 const struct ldb_val *dnsHostName = NULL;
846 const struct dsdb_class *computer_objectclass = NULL;
849 static const char *nc_attrs[] = {
850 "msDS-AllowedDNSSuffixes",
854 tmp_ctx = talloc_new(mem_ctx);
855 if (tmp_ctx == NULL) {
859 if (req->operation == LDB_MODIFY) {
860 msg = req->op.mod.message;
861 } else if (req->operation == LDB_ADD) {
862 msg = req->op.add.message;
865 if (implicit_validated_write_control != NULL) {
867 * The validated write control dispenses with ACL
868 * checks. We act as if we have an implicit Self Write
869 * privilege, but, assuming we don't have Write
870 * Property, still proceed with further validation
874 /* if we have wp, we can do whatever we like */
875 ret = acl_check_access_on_attribute(module,
881 if (ret == LDB_SUCCESS) {
882 talloc_free(tmp_ctx);
886 ret = acl_check_extended_right(tmp_ctx,
891 acl_user_token(module),
892 GUID_DRS_DNS_HOST_NAME,
896 if (ret != LDB_SUCCESS) {
897 dsdb_acl_debug(sd, acl_user_token(module),
901 talloc_free(tmp_ctx);
907 * If we have "validated write dnshostname", allow delete of
908 * any existing value (this keeps constrained delete to the
909 * same rules as unconstrained)
911 if (req->operation == LDB_MODIFY) {
912 struct ldb_result *acl_res = NULL;
914 static const char *acl_attrs[] = {
920 * If not add or replace (eg delete),
924 & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0)
926 talloc_free(tmp_ctx);
930 ret = dsdb_module_search_dn(module, tmp_ctx,
933 DSDB_FLAG_NEXT_MODULE |
934 DSDB_FLAG_AS_SYSTEM |
935 DSDB_SEARCH_SHOW_RECYCLED,
937 if (ret != LDB_SUCCESS) {
938 talloc_free(tmp_ctx);
942 search_res = acl_res->msgs[0];
943 } else if (req->operation == LDB_ADD) {
946 talloc_free(tmp_ctx);
947 return LDB_ERR_OPERATIONS_ERROR;
950 /* Check if the account has objectclass 'computer' or 'server'. */
952 schema = dsdb_get_schema(ldb, req);
953 if (schema == NULL) {
954 talloc_free(tmp_ctx);
955 return ldb_operr(ldb);
958 computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
959 if (computer_objectclass == NULL) {
960 talloc_free(tmp_ctx);
961 return ldb_operr(ldb);
964 is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
966 /* The account is not a computer -- check if it's a server. */
968 const struct dsdb_class *server_objectclass = NULL;
970 server_objectclass = dsdb_class_by_lDAPDisplayName(schema, "server");
971 if (server_objectclass == NULL) {
972 talloc_free(tmp_ctx);
973 return ldb_operr(ldb);
976 is_subclass = dsdb_is_subclass_of(schema, objectclass, server_objectclass);
978 /* Not a computer or server, so no need to validate. */
979 talloc_free(tmp_ctx);
984 if (req->operation == LDB_MODIFY) {
985 samAccountName = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
988 ret = dsdb_msg_get_single_value(msg,
993 if (ret != LDB_SUCCESS) {
994 talloc_free(tmp_ctx);
998 account_name_len = samAccountName->length;
999 if (account_name_len && samAccountName->data[account_name_len - 1] == '$') {
1000 /* Account for the '$' character. */
1004 /* Check for add or replace requests with no value. */
1005 if (el->num_values == 0) {
1006 talloc_free(tmp_ctx);
1007 return ldb_operr(ldb);
1009 dnsHostName = &el->values[0];
1011 dnsHostName_str = (const char *)dnsHostName->data;
1012 dns_host_name_len = dnsHostName->length;
1014 /* Check that sAMAccountName matches the new dNSHostName. */
1016 if (dns_host_name_len < account_name_len) {
1019 if (strncasecmp(dnsHostName_str,
1020 (const char *)samAccountName->data,
1021 account_name_len) != 0)
1026 dnsHostName_str += account_name_len;
1027 dns_host_name_len -= account_name_len;
1029 /* Check the '.' character */
1031 if (dns_host_name_len == 0 || *dnsHostName_str != '.') {
1036 --dns_host_name_len;
1038 /* Now we check the suffix. */
1040 ret = dsdb_find_nc_root(ldb,
1044 if (ret != LDB_SUCCESS) {
1045 talloc_free(tmp_ctx);
1049 nc_dns_name = samdb_dn_to_dns_domain(tmp_ctx, nc_root);
1050 if (nc_dns_name == NULL) {
1051 talloc_free(tmp_ctx);
1052 return ldb_operr(ldb);
1055 if (strlen(nc_dns_name) == dns_host_name_len &&
1056 strncasecmp(dnsHostName_str,
1058 dns_host_name_len) == 0)
1060 /* It matches -- success. */
1061 talloc_free(tmp_ctx);
1065 /* We didn't get a match, so now try msDS-AllowedDNSSuffixes. */
1067 ret = dsdb_module_search_dn(module, tmp_ctx,
1070 DSDB_FLAG_NEXT_MODULE |
1071 DSDB_FLAG_AS_SYSTEM |
1072 DSDB_SEARCH_SHOW_RECYCLED,
1074 if (ret != LDB_SUCCESS) {
1075 talloc_free(tmp_ctx);
1079 allowed_suffixes = ldb_msg_find_element(nc_res->msgs[0],
1080 "msDS-AllowedDNSSuffixes");
1081 if (allowed_suffixes == NULL) {
1085 for (i = 0; i < allowed_suffixes->num_values; ++i) {
1086 const struct ldb_val *suffix = &allowed_suffixes->values[i];
1088 if (suffix->length == dns_host_name_len &&
1089 strncasecmp(dnsHostName_str,
1090 (const char *)suffix->data,
1091 dns_host_name_len) == 0)
1093 /* It matches -- success. */
1094 talloc_free(tmp_ctx);
1100 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
1101 "acl: hostname validation failed for "
1102 "hostname[%.*s] account[%.*s]\n",
1103 (int)dnsHostName->length, dnsHostName->data,
1104 (int)samAccountName->length, samAccountName->data);
1105 talloc_free(tmp_ctx);
1106 return LDB_ERR_CONSTRAINT_VIOLATION;
1109 /* checks if modifications are allowed on "Member" attribute */
1110 static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
1111 struct ldb_module *module,
1112 struct ldb_request *req,
1113 struct security_descriptor *sd,
1114 struct dom_sid *sid,
1115 const struct dsdb_attribute *attr,
1116 const struct dsdb_class *objectclass)
1120 struct ldb_context *ldb = ldb_module_get_ctx(module);
1121 struct ldb_dn *user_dn;
1122 struct ldb_message_element *member_el;
1123 const struct ldb_message *msg = NULL;
1125 if (req->operation == LDB_MODIFY) {
1126 msg = req->op.mod.message;
1127 } else if (req->operation == LDB_ADD) {
1128 msg = req->op.add.message;
1130 return LDB_ERR_OPERATIONS_ERROR;
1133 /* if we have wp, we can do whatever we like */
1134 if (acl_check_access_on_attribute(module,
1139 attr, objectclass) == LDB_SUCCESS) {
1142 /* if we are adding/deleting ourselves, check for self membership */
1143 ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
1144 &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
1146 if (ret != LDB_SUCCESS) {
1149 member_el = ldb_msg_find_element(msg, "member");
1151 return ldb_operr(ldb);
1153 /* user can only remove oneself */
1154 if (member_el->num_values == 0) {
1155 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1157 for (i = 0; i < member_el->num_values; i++) {
1158 if (strcasecmp((const char *)member_el->values[i].data,
1159 ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
1160 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1163 ret = acl_check_extended_right(mem_ctx,
1168 acl_user_token(module),
1169 GUID_DRS_SELF_MEMBERSHIP,
1172 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1173 dsdb_acl_debug(sd, acl_user_token(module),
1181 static int acl_add(struct ldb_module *module, struct ldb_request *req)
1184 struct ldb_dn *parent;
1185 struct ldb_context *ldb;
1186 const struct dsdb_schema *schema;
1187 const struct dsdb_class *objectclass;
1188 const struct dsdb_class *computer_objectclass = NULL;
1189 const struct ldb_message_element *oc_el = NULL;
1190 struct ldb_message_element sorted_oc_el;
1191 struct ldb_control *sd_ctrl = NULL;
1192 struct ldb_message_element *el;
1193 unsigned int instanceType = 0;
1194 struct dsdb_control_calculated_default_sd *control_sd = NULL;
1195 const struct dsdb_attribute *attr = NULL;
1196 const char **must_contain = NULL;
1197 const struct ldb_message *msg = req->op.add.message;
1198 const struct dom_sid *domain_sid = NULL;
1200 bool attribute_authorization;
1203 if (ldb_dn_is_special(msg->dn)) {
1204 return ldb_next_request(module, req);
1207 if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
1209 return ldb_next_request(module, req);
1212 ldb = ldb_module_get_ctx(module);
1213 domain_sid = samdb_domain_sid(ldb);
1215 parent = ldb_dn_get_parent(req, msg->dn);
1216 if (parent == NULL) {
1217 return ldb_oom(ldb);
1220 schema = dsdb_get_schema(ldb, req);
1222 return ldb_operr(ldb);
1225 /* Find the objectclass of the new account. */
1227 oc_el = ldb_msg_find_element(msg, "objectclass");
1228 if (oc_el == NULL) {
1229 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1230 "acl: unable to find or validate structural objectClass on %s\n",
1231 ldb_dn_get_linearized(msg->dn));
1232 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
1235 schema = dsdb_get_schema(ldb, req);
1236 if (schema == NULL) {
1237 return ldb_operr(ldb);
1240 ret = dsdb_sort_objectClass_attr(ldb, schema, oc_el, req, &sorted_oc_el);
1241 if (ret != LDB_SUCCESS) {
1245 objectclass = dsdb_get_last_structural_class(schema, &sorted_oc_el);
1246 if (objectclass == NULL) {
1247 return ldb_operr(ldb);
1250 el = ldb_msg_find_element(msg, "instanceType");
1251 if ((el != NULL) && (el->num_values != 1)) {
1252 ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
1253 return LDB_ERR_UNWILLING_TO_PERFORM;
1256 instanceType = ldb_msg_find_attr_as_uint(msg,
1258 if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
1259 static const char *no_attrs[] = { NULL };
1260 struct ldb_result *partition_res;
1261 struct ldb_dn *partitions_dn;
1263 partitions_dn = samdb_partitions_dn(ldb, req);
1264 if (!partitions_dn) {
1265 ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
1266 return LDB_ERR_UNWILLING_TO_PERFORM;
1269 ret = dsdb_module_search(module, req, &partition_res,
1270 partitions_dn, LDB_SCOPE_ONELEVEL,
1272 DSDB_FLAG_NEXT_MODULE |
1273 DSDB_FLAG_AS_SYSTEM |
1274 DSDB_SEARCH_ONE_ONLY |
1275 DSDB_SEARCH_SHOW_RECYCLED,
1277 "(&(nCName=%s)(objectClass=crossRef))",
1278 ldb_dn_get_linearized(msg->dn));
1280 if (ret == LDB_SUCCESS) {
1281 /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1282 ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
1284 &objectclass->schemaIDGUID, req);
1285 if (ret != LDB_SUCCESS) {
1286 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1287 "acl: ACL check failed on crossRef object %s: %s\n",
1288 ldb_dn_get_linearized(partition_res->msgs[0]->dn),
1289 ldb_errstring(ldb));
1294 * TODO: Remaining checks, like if we are
1295 * the naming master etc need to be handled
1296 * in the instanceType module
1298 /* Note - do we need per-attribute checks? */
1299 return ldb_next_request(module, req);
1302 /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1303 ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
1304 SEC_ADS_CREATE_CHILD,
1305 &objectclass->schemaIDGUID, req);
1306 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1307 ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
1309 /* Allow provision bootstrap */
1312 if (ret != LDB_SUCCESS) {
1313 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1314 "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
1315 ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
1320 * TODO: Remaining checks, like if we are the naming
1321 * master and adding the crossRef object need to be
1322 * handled in the instanceType module
1325 ret = dsdb_module_check_access_on_dn(module, req, parent,
1326 SEC_ADS_CREATE_CHILD,
1327 &objectclass->schemaIDGUID, req);
1328 if (ret != LDB_SUCCESS) {
1329 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1330 "acl: unable to get access to %s\n",
1331 ldb_dn_get_linearized(msg->dn));
1336 attribute_authorization = dsdb_attribute_authz_on_ldap_add(module,
1339 if (!attribute_authorization) {
1340 /* Skip the remaining checks */
1344 /* Check if we have computer objectclass. */
1345 computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
1346 if (computer_objectclass == NULL) {
1347 return ldb_operr(ldb);
1350 is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
1353 * This object is not a computer (or derived from computer), so
1354 * skip the remaining checks.
1360 * we have established we have CC right, now check per-attribute
1361 * access based on the default SD
1364 sd_ctrl = ldb_request_get_control(req,
1365 DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID);
1366 if (sd_ctrl == NULL) {
1371 TALLOC_CTX *tmp_ctx = talloc_new(req);
1372 control_sd = (struct dsdb_control_calculated_default_sd *) sd_ctrl->data;
1373 DBG_DEBUG("Received cookie descriptor %s\n\n",
1374 sddl_encode(tmp_ctx, control_sd->default_sd, domain_sid));
1375 TALLOC_FREE(tmp_ctx);
1376 /* Mark the "change" control as uncritical (done) */
1377 sd_ctrl->critical = false;
1381 * At this point we do not yet have the object's SID, so we
1382 * leave it empty. It is irrelevant, as it is used to expand
1383 * Principal-Self, and rights granted to PS will have no effect
1386 /* check if we have WD, no need to perform other attribute checks if we do */
1387 attr = dsdb_attribute_by_lDAPDisplayName(schema, "nTSecurityDescriptor");
1389 return ldb_operr(ldb);
1392 if (control_sd->specified_sacl) {
1393 const struct security_token *token = acl_user_token(module);
1394 bool has_priv = security_token_has_privilege(token, SEC_PRIV_SECURITY);
1396 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1400 ret = acl_check_access_on_attribute(module,
1402 control_sd->default_sd,
1407 if (ret == LDB_SUCCESS) {
1411 if (control_sd->specified_sd) {
1412 bool block_owner_rights = dsdb_block_owner_implicit_rights(module,
1415 if (block_owner_rights) {
1416 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1417 "Object %s has no SD modification rights",
1418 ldb_dn_get_linearized(msg->dn));
1419 dsdb_acl_debug(control_sd->default_sd,
1420 acl_user_token(module),
1424 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1429 must_contain = dsdb_full_attribute_list(req, schema, &sorted_oc_el,
1430 DSDB_SCHEMA_ALL_MUST);
1431 for (i=0; i < msg->num_elements; i++) {
1432 el = &msg->elements[i];
1434 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1435 if (attr == NULL && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1436 ldb_asprintf_errstring(ldb, "acl_add: attribute '%s' "
1437 "on entry '%s' was not found in the schema!",
1439 ldb_dn_get_linearized(msg->dn));
1440 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1445 bool found = str_list_check(must_contain, attr->lDAPDisplayName);
1446 /* do not check the mandatory attributes */
1452 if (ldb_attr_cmp("dBCSPwd", el->name) == 0 ||
1453 ldb_attr_cmp("unicodePwd", el->name) == 0 ||
1454 ldb_attr_cmp("userPassword", el->name) == 0 ||
1455 ldb_attr_cmp("clearTextPassword", el->name) == 0) {
1457 } else if (ldb_attr_cmp("member", el->name) == 0) {
1458 ret = acl_check_self_membership(req,
1461 control_sd->default_sd,
1465 if (ret != LDB_SUCCESS) {
1468 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
1469 ret = acl_check_spn(req,
1473 control_sd->default_sd,
1478 if (ret != LDB_SUCCESS) {
1479 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1480 "Object %s cannot be created with spn",
1481 ldb_dn_get_linearized(msg->dn));
1482 dsdb_acl_debug(control_sd->default_sd,
1483 acl_user_token(module),
1489 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
1490 ret = acl_check_dns_host_name(req,
1494 control_sd->default_sd,
1499 if (ret != LDB_SUCCESS) {
1500 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1501 "Object %s cannot be created with dnsHostName",
1502 ldb_dn_get_linearized(msg->dn));
1503 dsdb_acl_debug(control_sd->default_sd,
1504 acl_user_token(module),
1511 ret = acl_check_access_on_attribute(module,
1513 control_sd->default_sd,
1518 if (ret != LDB_SUCCESS) {
1519 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1520 "Object %s has no write property access",
1521 ldb_dn_get_linearized(msg->dn));
1522 dsdb_acl_debug(control_sd->default_sd,
1523 acl_user_token(module),
1527 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1533 return ldb_next_request(module, req);
1536 static int acl_check_password_rights(
1537 TALLOC_CTX *mem_ctx,
1538 struct ldb_module *module,
1539 struct ldb_request *req,
1540 struct security_descriptor *sd,
1541 struct dom_sid *sid,
1542 const struct dsdb_class *objectclass,
1544 struct dsdb_control_password_acl_validation **control_for_response)
1546 int ret = LDB_SUCCESS;
1547 unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
1548 unsigned int del_val_cnt = 0, add_val_cnt = 0;
1549 struct ldb_message_element *el;
1550 struct ldb_message *msg;
1551 struct ldb_control *c = NULL;
1552 const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
1553 "unicodePwd", NULL }, **l;
1554 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1555 struct dsdb_control_password_acl_validation *pav = NULL;
1557 if (tmp_ctx == NULL) {
1558 return LDB_ERR_OPERATIONS_ERROR;
1561 pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
1563 talloc_free(tmp_ctx);
1564 return LDB_ERR_OPERATIONS_ERROR;
1567 * Set control_for_response to pav so it can be added to the response
1568 * and be passed up to the audit_log module which uses it to identify
1569 * password reset attempts.
1571 *control_for_response = pav;
1573 c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
1575 pav->pwd_reset = false;
1578 * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1579 * have a user password change and not a set as the message
1580 * looks like. In it's value blob it contains the NT and/or LM
1581 * hash of the old password specified by the user. This control
1582 * is used by the SAMR and "kpasswd" password change mechanisms.
1584 * This control can't be used by real LDAP clients,
1585 * the only caller is samdb_set_password_internal(),
1586 * so we don't have to strict verification of the input.
1588 ret = acl_check_extended_right(tmp_ctx,
1593 acl_user_token(module),
1594 GUID_DRS_USER_CHANGE_PASSWORD,
1595 SEC_ADS_CONTROL_ACCESS,
1600 c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1602 pav->pwd_reset = true;
1605 * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
1606 * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1607 * have a force password set.
1608 * This control is used by the SAMR/NETLOGON/LSA password
1611 * This control can't be used by real LDAP clients,
1612 * the only caller is samdb_set_password_internal(),
1613 * so we don't have to strict verification of the input.
1615 ret = acl_check_extended_right(tmp_ctx,
1620 acl_user_token(module),
1621 GUID_DRS_FORCE_CHANGE_PASSWORD,
1622 SEC_ADS_CONTROL_ACCESS,
1627 el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1630 * dBCSPwd is only allowed with a control.
1632 talloc_free(tmp_ctx);
1633 return LDB_ERR_UNWILLING_TO_PERFORM;
1636 msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
1638 return ldb_module_oom(module);
1640 for (l = passwordAttrs; *l != NULL; l++) {
1641 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
1645 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
1646 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1648 del_val_cnt += el->num_values;
1650 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
1652 add_val_cnt += el->num_values;
1654 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1657 ldb_msg_remove_element(msg, el);
1661 /* single deletes will be handled by the "password_hash" LDB module
1662 * later in the stack, so we let it though here */
1663 if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
1664 talloc_free(tmp_ctx);
1669 if (rep_attr_cnt > 0) {
1670 pav->pwd_reset = true;
1672 ret = acl_check_extended_right(tmp_ctx,
1677 acl_user_token(module),
1678 GUID_DRS_FORCE_CHANGE_PASSWORD,
1679 SEC_ADS_CONTROL_ACCESS,
1684 if (add_attr_cnt != del_attr_cnt) {
1685 pav->pwd_reset = true;
1687 ret = acl_check_extended_right(tmp_ctx,
1692 acl_user_token(module),
1693 GUID_DRS_FORCE_CHANGE_PASSWORD,
1694 SEC_ADS_CONTROL_ACCESS,
1699 if (add_val_cnt == 1 && del_val_cnt == 1) {
1700 pav->pwd_reset = false;
1702 ret = acl_check_extended_right(tmp_ctx,
1707 acl_user_token(module),
1708 GUID_DRS_USER_CHANGE_PASSWORD,
1709 SEC_ADS_CONTROL_ACCESS,
1711 /* Very strange, but we get constraint violation in this case */
1712 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1713 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1718 if (add_val_cnt == 1 && del_val_cnt == 0) {
1719 pav->pwd_reset = true;
1721 ret = acl_check_extended_right(tmp_ctx,
1726 acl_user_token(module),
1727 GUID_DRS_FORCE_CHANGE_PASSWORD,
1728 SEC_ADS_CONTROL_ACCESS,
1730 /* Very strange, but we get constraint violation in this case */
1731 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1732 ret = LDB_ERR_CONSTRAINT_VIOLATION;
1738 * Everything else is handled by the password_hash module where it will
1739 * fail, but with the correct error code when the module is again
1740 * checking the attributes. As the change request will lack the
1741 * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
1742 * any modification attempt that went this way will be rejected.
1745 talloc_free(tmp_ctx);
1749 if (ret != LDB_SUCCESS) {
1750 dsdb_acl_debug(sd, acl_user_token(module),
1751 req->op.mod.message->dn,
1754 talloc_free(tmp_ctx);
1758 ret = ldb_request_add_control(req,
1759 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
1760 if (ret != LDB_SUCCESS) {
1761 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1762 "Unable to register ACL validation control!\n");
1769 * Context needed by acl_callback
1771 struct acl_callback_context {
1772 struct ldb_request *request;
1773 struct ldb_module *module;
1777 * @brief Copy the password validation control to the reply.
1779 * Copy the dsdb_control_password_acl_validation control from the request,
1780 * to the reply. The control is used by the audit_log module to identify
1783 * @param req the ldb request.
1784 * @param ares the result, updated with the control.
1786 static void copy_password_acl_validation_control(
1787 struct ldb_request *req,
1788 struct ldb_reply *ares)
1790 struct ldb_control *pav_ctrl = NULL;
1791 struct dsdb_control_password_acl_validation *pav = NULL;
1793 pav_ctrl = ldb_request_get_control(
1795 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1796 if (pav_ctrl == NULL) {
1800 pav = talloc_get_type_abort(
1802 struct dsdb_control_password_acl_validation);
1806 ldb_reply_add_control(
1808 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
1813 * @brief call back function for acl_modify.
1815 * Calls acl_copy to copy the dsdb_control_password_acl_validation from
1816 * the request to the reply.
1818 * @param req the ldb_request.
1819 * @param ares the operation result.
1821 * @return the LDB_STATUS
1823 static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
1825 struct acl_callback_context *ac = NULL;
1827 ac = talloc_get_type(req->context, struct acl_callback_context);
1830 return ldb_module_done(
1834 LDB_ERR_OPERATIONS_ERROR);
1837 /* pass on to the callback */
1838 switch (ares->type) {
1839 case LDB_REPLY_ENTRY:
1840 return ldb_module_send_entry(
1845 case LDB_REPLY_REFERRAL:
1846 return ldb_module_send_referral(
1850 case LDB_REPLY_DONE:
1852 * Copy the ACL control from the request to the response
1854 copy_password_acl_validation_control(req, ares);
1855 return ldb_module_done(
1863 return LDB_ERR_OPERATIONS_ERROR;
1867 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
1870 struct ldb_context *ldb = ldb_module_get_ctx(module);
1871 const struct dsdb_schema *schema;
1873 const struct dsdb_class *objectclass;
1874 struct ldb_result *acl_res;
1875 struct security_descriptor *sd;
1876 struct dom_sid *sid = NULL;
1877 struct ldb_control *is_undelete;
1878 struct ldb_control *implicit_validated_write_control = NULL;
1880 bool password_rights_checked = false;
1881 TALLOC_CTX *tmp_ctx;
1882 const struct ldb_message *msg = req->op.mod.message;
1883 static const char *acl_attrs[] = {
1884 "nTSecurityDescriptor",
1889 struct acl_callback_context *context = NULL;
1890 struct ldb_request *new_req = NULL;
1891 struct dsdb_control_password_acl_validation *pav = NULL;
1892 struct ldb_control **controls = NULL;
1894 if (ldb_dn_is_special(msg->dn)) {
1895 return ldb_next_request(module, req);
1898 is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1900 implicit_validated_write_control = ldb_request_get_control(
1901 req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
1902 if (implicit_validated_write_control != NULL) {
1903 implicit_validated_write_control->critical = 0;
1906 /* Don't print this debug statement if elements[0].name is going to be NULL */
1907 if (msg->num_elements > 0) {
1908 DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
1910 if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
1912 return ldb_next_request(module, req);
1915 tmp_ctx = talloc_new(req);
1916 if (tmp_ctx == NULL) {
1917 return ldb_oom(ldb);
1920 ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
1922 DSDB_FLAG_NEXT_MODULE |
1923 DSDB_FLAG_AS_SYSTEM |
1924 DSDB_SEARCH_SHOW_RECYCLED,
1927 if (ret != LDB_SUCCESS) {
1931 userPassword = dsdb_user_password_support(module, req, req);
1933 schema = dsdb_get_schema(ldb, tmp_ctx);
1935 talloc_free(tmp_ctx);
1936 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1937 "acl_modify: Error obtaining schema.");
1940 ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1941 if (ret != LDB_SUCCESS) {
1942 talloc_free(tmp_ctx);
1943 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1944 "acl_modify: Error retrieving security descriptor.");
1946 /* Theoretically we pass the check if the object has no sd */
1951 objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1953 talloc_free(tmp_ctx);
1954 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1955 "acl_modify: Error retrieving object class for GUID.");
1957 sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1958 for (i=0; i < msg->num_elements; i++) {
1959 const struct ldb_message_element *el = &msg->elements[i];
1960 const struct dsdb_attribute *attr;
1963 * This basic attribute existence check with the right errorcode
1964 * is needed since this module is the first one which requests
1965 * schema attribute information.
1966 * The complete attribute checking is done in the
1967 * "objectclass_attrs" module behind this one.
1969 * NOTE: "clearTextPassword" is not defined in the schema.
1971 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1972 if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1973 ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
1974 "on entry '%s' was not found in the schema!",
1975 req->op.mod.message->elements[i].name,
1976 ldb_dn_get_linearized(req->op.mod.message->dn));
1977 ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1981 if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
1982 uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1983 uint32_t access_mask = 0;
1985 bool block_owner_rights;
1986 enum implicit_owner_rights implicit_owner_rights;
1988 if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1989 access_mask |= SEC_STD_WRITE_OWNER;
1991 if (sd_flags & SECINFO_DACL) {
1992 access_mask |= SEC_STD_WRITE_DAC;
1994 if (sd_flags & SECINFO_SACL) {
1995 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1998 block_owner_rights = !dsdb_module_am_administrator(module);
2000 if (block_owner_rights) {
2001 block_owner_rights = dsdb_block_owner_implicit_rights(module,
2005 if (block_owner_rights) {
2006 block_owner_rights = samdb_find_attribute(ldb,
2012 implicit_owner_rights = block_owner_rights ?
2013 IMPLICIT_OWNER_READ_CONTROL_RIGHTS :
2014 IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS;
2016 ret = acl_check_access_on_attribute_implicit_owner(module,
2023 implicit_owner_rights);
2024 if (ret != LDB_SUCCESS) {
2025 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2026 "Object %s has no write dacl access\n",
2027 ldb_dn_get_linearized(msg->dn));
2029 acl_user_token(module),
2033 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2036 } else if (ldb_attr_cmp("member", el->name) == 0) {
2037 ret = acl_check_self_membership(tmp_ctx,
2044 if (ret != LDB_SUCCESS) {
2047 } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
2048 /* this one is not affected by any rights, we should let it through
2049 so that passwords_hash returns the correct error */
2051 } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
2052 (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
2053 ldb_attr_cmp("clearTextPassword", el->name) == 0) {
2055 * Ideally we would do the acl_check_password_rights
2056 * before we checked the other attributes, i.e. in a
2057 * loop before the current one.
2058 * Have not done this as yet in order to limit the size
2059 * of the change. To limit the possibility of breaking
2062 if (password_rights_checked) {
2065 ret = acl_check_password_rights(tmp_ctx,
2073 if (ret != LDB_SUCCESS) {
2076 password_rights_checked = true;
2077 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
2078 ret = acl_check_spn(tmp_ctx,
2086 implicit_validated_write_control);
2087 if (ret != LDB_SUCCESS) {
2090 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
2091 ret = acl_check_dns_host_name(tmp_ctx,
2099 implicit_validated_write_control);
2100 if (ret != LDB_SUCCESS) {
2103 } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
2105 * in case of undelete op permissions on
2106 * isDeleted are irrelevant and
2107 * distinguishedName is removed by the
2108 * tombstone_reanimate module
2111 } else if (implicit_validated_write_control != NULL) {
2112 /* Allow the update. */
2115 ret = acl_check_access_on_attribute(module,
2122 if (ret != LDB_SUCCESS) {
2123 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2124 "Object %s has no write property access\n",
2125 ldb_dn_get_linearized(msg->dn));
2127 acl_user_token(module),
2131 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2138 talloc_free(tmp_ctx);
2139 context = talloc_zero(req, struct acl_callback_context);
2141 if (context == NULL) {
2142 return ldb_oom(ldb);
2144 context->request = req;
2145 context->module = module;
2146 ret = ldb_build_mod_req(
2150 req->op.mod.message,
2155 if (ret != LDB_SUCCESS) {
2158 return ldb_next_request(module, new_req);
2160 talloc_free(tmp_ctx);
2162 * We copy the pav into the result, so that the password reset
2163 * logging code in audit_log can log failed password reset attempts.
2166 struct ldb_control *control = NULL;
2168 controls = talloc_zero_array(req, struct ldb_control *, 2);
2169 if (controls == NULL) {
2170 return ldb_oom(ldb);
2173 control = talloc(controls, struct ldb_control);
2175 if (control == NULL) {
2176 return ldb_oom(ldb);
2179 control->oid= talloc_strdup(
2181 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
2182 if (control->oid == NULL) {
2183 return ldb_oom(ldb);
2185 control->critical = false;
2186 control->data = pav;
2187 *controls = control;
2189 return ldb_module_done(req, controls, NULL, ret);
2192 /* similar to the modify for the time being.
2193 * We need to consider the special delete tree case, though - TODO */
2194 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
2197 struct ldb_dn *parent;
2198 struct ldb_context *ldb;
2199 struct ldb_dn *nc_root;
2200 const struct dsdb_schema *schema;
2201 const struct dsdb_class *objectclass;
2202 struct security_descriptor *sd = NULL;
2203 struct dom_sid *sid = NULL;
2204 struct ldb_result *acl_res;
2205 static const char *acl_attrs[] = {
2206 "nTSecurityDescriptor",
2212 if (ldb_dn_is_special(req->op.del.dn)) {
2213 return ldb_next_request(module, req);
2216 if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
2218 return ldb_next_request(module, req);
2221 DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
2223 ldb = ldb_module_get_ctx(module);
2225 parent = ldb_dn_get_parent(req, req->op.del.dn);
2226 if (parent == NULL) {
2227 return ldb_oom(ldb);
2230 /* Make sure we aren't deleting a NC */
2232 ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
2233 if (ret != LDB_SUCCESS) {
2236 if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
2237 talloc_free(nc_root);
2238 DEBUG(10,("acl:deleting a NC\n"));
2239 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2240 return ldb_module_done(req, NULL, NULL,
2241 LDB_ERR_UNWILLING_TO_PERFORM);
2243 talloc_free(nc_root);
2245 ret = dsdb_module_search_dn(module, req, &acl_res,
2246 req->op.del.dn, acl_attrs,
2247 DSDB_FLAG_NEXT_MODULE |
2248 DSDB_FLAG_AS_SYSTEM |
2249 DSDB_SEARCH_SHOW_RECYCLED, req);
2250 /* we should be able to find the parent */
2251 if (ret != LDB_SUCCESS) {
2252 DEBUG(10,("acl: failed to find object %s\n",
2253 ldb_dn_get_linearized(req->op.rename.olddn)));
2257 ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2258 if (ret != LDB_SUCCESS) {
2259 return ldb_operr(ldb);
2262 return ldb_operr(ldb);
2265 schema = dsdb_get_schema(ldb, req);
2267 return ldb_operr(ldb);
2270 sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2272 objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2274 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2275 "acl_modify: Error retrieving object class for GUID.");
2278 if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
2279 ret = acl_check_access_on_objectclass(module, req, sd, sid,
2280 SEC_ADS_DELETE_TREE,
2282 if (ret != LDB_SUCCESS) {
2286 return ldb_next_request(module, req);
2289 /* First check if we have delete object right */
2290 ret = acl_check_access_on_objectclass(module, req, sd, sid,
2293 if (ret == LDB_SUCCESS) {
2294 return ldb_next_request(module, req);
2297 /* Nope, we don't have delete object. Lets check if we have delete
2298 * child on the parent */
2299 ret = dsdb_module_check_access_on_dn(module, req, parent,
2300 SEC_ADS_DELETE_CHILD,
2301 &objectclass->schemaIDGUID,
2303 if (ret != LDB_SUCCESS) {
2307 return ldb_next_request(module, req);
2309 static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
2310 struct ldb_module *module,
2311 struct ldb_request *req,
2312 struct ldb_dn *nc_root)
2315 struct ldb_result *acl_res;
2316 struct security_descriptor *sd = NULL;
2317 struct dom_sid *sid = NULL;
2318 const struct dsdb_schema *schema = NULL;
2319 const struct dsdb_class *objectclass = NULL;
2320 struct ldb_context *ldb = ldb_module_get_ctx(module);
2321 static const char *acl_attrs[] = {
2322 "nTSecurityDescriptor",
2328 ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
2330 DSDB_FLAG_NEXT_MODULE |
2331 DSDB_FLAG_AS_SYSTEM |
2332 DSDB_SEARCH_SHOW_RECYCLED, req);
2333 if (ret != LDB_SUCCESS) {
2334 DEBUG(10,("acl: failed to find object %s\n",
2335 ldb_dn_get_linearized(nc_root)));
2339 ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
2340 sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
2341 schema = dsdb_get_schema(ldb, req);
2343 return LDB_ERR_OPERATIONS_ERROR;
2345 objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2346 if (ret != LDB_SUCCESS || !sd) {
2347 return ldb_operr(ldb_module_get_ctx(module));
2349 return acl_check_extended_right(mem_ctx,
2354 acl_user_token(module),
2355 GUID_DRS_REANIMATE_TOMBSTONE,
2356 SEC_ADS_CONTROL_ACCESS, sid);
2359 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
2362 struct ldb_dn *oldparent;
2363 struct ldb_dn *newparent;
2364 const struct dsdb_schema *schema;
2365 const struct dsdb_class *objectclass;
2366 const struct dsdb_attribute *attr = NULL;
2367 struct ldb_context *ldb;
2368 struct security_descriptor *sd = NULL;
2369 struct dom_sid *sid = NULL;
2370 struct ldb_result *acl_res;
2371 struct ldb_dn *nc_root;
2372 struct ldb_control *is_undelete;
2373 TALLOC_CTX *tmp_ctx;
2374 const char *rdn_name;
2375 static const char *acl_attrs[] = {
2376 "nTSecurityDescriptor",
2382 if (ldb_dn_is_special(req->op.rename.olddn)) {
2383 return ldb_next_request(module, req);
2386 DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
2387 if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
2389 return ldb_next_request(module, req);
2392 ldb = ldb_module_get_ctx(module);
2394 tmp_ctx = talloc_new(req);
2395 if (tmp_ctx == NULL) {
2396 return ldb_oom(ldb);
2399 oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
2400 if (oldparent == NULL) {
2401 return ldb_oom(ldb);
2403 newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
2404 if (newparent == NULL) {
2405 return ldb_oom(ldb);
2408 /* Make sure we aren't renaming/moving a NC */
2410 ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
2411 if (ret != LDB_SUCCESS) {
2414 if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
2415 talloc_free(nc_root);
2416 DEBUG(10,("acl:renaming/moving a NC\n"));
2417 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2418 return ldb_module_done(req, NULL, NULL,
2419 LDB_ERR_UNWILLING_TO_PERFORM);
2422 /* special check for undelete operation */
2423 is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
2424 if (is_undelete != NULL) {
2425 is_undelete->critical = 0;
2426 ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
2427 if (ret != LDB_SUCCESS) {
2428 talloc_free(tmp_ctx);
2432 talloc_free(nc_root);
2434 /* Look for the parent */
2436 ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
2437 req->op.rename.olddn, acl_attrs,
2438 DSDB_FLAG_NEXT_MODULE |
2439 DSDB_FLAG_AS_SYSTEM |
2440 DSDB_SEARCH_SHOW_RECYCLED, req);
2441 /* we should be able to find the parent */
2442 if (ret != LDB_SUCCESS) {
2443 DEBUG(10,("acl: failed to find object %s\n",
2444 ldb_dn_get_linearized(req->op.rename.olddn)));
2445 talloc_free(tmp_ctx);
2449 ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2450 if (ret != LDB_SUCCESS) {
2451 talloc_free(tmp_ctx);
2452 return ldb_operr(ldb);
2455 talloc_free(tmp_ctx);
2456 return ldb_operr(ldb);
2459 schema = dsdb_get_schema(ldb, acl_res);
2461 talloc_free(tmp_ctx);
2462 return ldb_operr(ldb);
2465 sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2467 objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2469 talloc_free(tmp_ctx);
2470 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2471 "acl_modify: Error retrieving object class for GUID.");
2474 attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
2476 talloc_free(tmp_ctx);
2477 return ldb_operr(ldb);
2480 ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2483 if (ret != LDB_SUCCESS) {
2484 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2485 "Object %s has no wp on %s\n",
2486 ldb_dn_get_linearized(req->op.rename.olddn),
2487 attr->lDAPDisplayName);
2489 acl_user_token(module),
2490 req->op.rename.olddn,
2493 talloc_free(tmp_ctx);
2494 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2497 rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
2498 if (rdn_name == NULL) {
2499 talloc_free(tmp_ctx);
2500 return ldb_operr(ldb);
2503 attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2505 talloc_free(tmp_ctx);
2506 return ldb_operr(ldb);
2509 ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2512 if (ret != LDB_SUCCESS) {
2513 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2514 "Object %s has no wp on %s\n",
2515 ldb_dn_get_linearized(req->op.rename.olddn),
2516 attr->lDAPDisplayName);
2518 acl_user_token(module),
2519 req->op.rename.olddn,
2522 talloc_free(tmp_ctx);
2523 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2526 if (ldb_dn_compare(oldparent, newparent) == 0) {
2527 /* regular rename, not move, nothing more to do */
2528 talloc_free(tmp_ctx);
2529 return ldb_next_request(module, req);
2532 /* new parent should have create child */
2533 ret = dsdb_module_check_access_on_dn(module, req, newparent,
2534 SEC_ADS_CREATE_CHILD,
2535 &objectclass->schemaIDGUID, req);
2536 if (ret != LDB_SUCCESS) {
2537 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2538 "acl:access_denied renaming %s",
2539 ldb_dn_get_linearized(req->op.rename.olddn));
2540 talloc_free(tmp_ctx);
2544 /* do we have delete object on the object? */
2545 /* this access is not necessary for undelete ops */
2546 if (is_undelete == NULL) {
2547 ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
2550 if (ret == LDB_SUCCESS) {
2551 talloc_free(tmp_ctx);
2552 return ldb_next_request(module, req);
2554 /* what about delete child on the current parent */
2555 ret = dsdb_module_check_access_on_dn(module, req, oldparent,
2556 SEC_ADS_DELETE_CHILD,
2557 &objectclass->schemaIDGUID,
2559 if (ret != LDB_SUCCESS) {
2560 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2561 "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
2562 talloc_free(tmp_ctx);
2563 return ldb_module_done(req, NULL, NULL, ret);
2566 talloc_free(tmp_ctx);
2568 return ldb_next_request(module, req);
2571 static int acl_search_update_confidential_attrs(struct acl_context *ac,
2572 struct acl_private *data)
2574 struct dsdb_attribute *a;
2577 if (data->acl_search) {
2579 * If acl:search is activated, the acl_read module
2580 * protects confidential attributes.
2585 if ((ac->schema == data->cached_schema_ptr) &&
2586 (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
2591 data->cached_schema_ptr = NULL;
2592 data->cached_schema_loaded_usn = 0;
2593 data->cached_schema_metadata_usn = 0;
2594 TALLOC_FREE(data->confidential_attrs);
2596 if (ac->schema == NULL) {
2600 for (a = ac->schema->attributes; a; a = a->next) {
2601 const char **attrs = data->confidential_attrs;
2603 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
2607 attrs = talloc_realloc(data, attrs, const char *, n + 2);
2608 if (attrs == NULL) {
2609 TALLOC_FREE(data->confidential_attrs);
2610 return ldb_module_oom(ac->module);
2613 attrs[n] = a->lDAPDisplayName;
2617 data->confidential_attrs = attrs;
2620 data->cached_schema_ptr = ac->schema;
2621 data->cached_schema_metadata_usn = ac->schema->metadata_usn;
2626 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2628 struct acl_context *ac;
2629 struct acl_private *data;
2630 struct ldb_result *acl_res;
2631 static const char *acl_attrs[] = {
2633 "nTSecurityDescriptor",
2640 ac = talloc_get_type(req->context, struct acl_context);
2641 data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2643 return ldb_module_done(ac->req, NULL, NULL,
2644 LDB_ERR_OPERATIONS_ERROR);
2646 if (ares->error != LDB_SUCCESS) {
2647 return ldb_module_done(ac->req, ares->controls,
2648 ares->response, ares->error);
2651 switch (ares->type) {
2652 case LDB_REPLY_ENTRY:
2653 if (ac->constructed_attrs) {
2654 ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn,
2656 DSDB_FLAG_NEXT_MODULE |
2657 DSDB_FLAG_AS_SYSTEM |
2658 DSDB_SEARCH_SHOW_RECYCLED,
2660 if (ret != LDB_SUCCESS) {
2661 return ldb_module_done(ac->req, NULL, NULL, ret);
2665 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
2666 ret = acl_allowedAttributes(ac->module, ac->schema,
2669 if (ret != LDB_SUCCESS) {
2670 return ldb_module_done(ac->req, NULL, NULL, ret);
2674 if (ac->allowedChildClasses) {
2675 ret = acl_childClasses(ac->module, ac->schema,
2678 "allowedChildClasses");
2679 if (ret != LDB_SUCCESS) {
2680 return ldb_module_done(ac->req, NULL, NULL, ret);
2684 if (ac->allowedChildClassesEffective) {
2685 ret = acl_childClassesEffective(ac->module, ac->schema,
2688 if (ret != LDB_SUCCESS) {
2689 return ldb_module_done(ac->req, NULL, NULL, ret);
2693 if (ac->sDRightsEffective) {
2694 ret = acl_sDRightsEffective(ac->module,
2697 if (ret != LDB_SUCCESS) {
2698 return ldb_module_done(ac->req, NULL, NULL, ret);
2703 return ldb_module_send_entry(ac->req, ares->message,
2707 if (ac->am_system) {
2708 return ldb_module_send_entry(ac->req, ares->message,
2712 if (ac->am_administrator) {
2713 return ldb_module_send_entry(ac->req, ares->message,
2717 if (data->confidential_attrs != NULL) {
2718 for (i = 0; data->confidential_attrs[i]; i++) {
2719 ldb_msg_remove_attr(ares->message,
2720 data->confidential_attrs[i]);
2724 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
2726 case LDB_REPLY_REFERRAL:
2727 return ldb_module_send_referral(ac->req, ares->referral);
2729 case LDB_REPLY_DONE:
2730 return ldb_module_done(ac->req, ares->controls,
2731 ares->response, LDB_SUCCESS);
2737 static int acl_search(struct ldb_module *module, struct ldb_request *req)
2739 struct ldb_context *ldb;
2740 struct acl_context *ac;
2741 struct ldb_parse_tree *down_tree = req->op.search.tree;
2742 struct ldb_request *down_req;
2743 struct acl_private *data;
2746 bool modify_search = true;
2748 if (ldb_dn_is_special(req->op.search.base)) {
2749 return ldb_next_request(module, req);
2752 ldb = ldb_module_get_ctx(module);
2754 ac = talloc_zero(req, struct acl_context);
2756 return ldb_oom(ldb);
2758 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
2760 ac->module = module;
2762 ac->am_system = dsdb_module_am_system(module);
2763 ac->am_administrator = dsdb_module_am_administrator(module);
2764 ac->constructed_attrs = false;
2765 ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
2766 ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
2767 ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
2768 ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
2769 ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
2770 ac->schema = dsdb_get_schema(ldb, ac);
2772 ac->constructed_attrs |= ac->allowedAttributes;
2773 ac->constructed_attrs |= ac->allowedChildClasses;
2774 ac->constructed_attrs |= ac->allowedChildClassesEffective;
2775 ac->constructed_attrs |= ac->allowedAttributesEffective;
2776 ac->constructed_attrs |= ac->sDRightsEffective;
2779 modify_search = false;
2781 if (ac->am_system) {
2782 modify_search = false;
2785 if (!ac->constructed_attrs && !modify_search) {
2787 return ldb_next_request(module, req);
2790 data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2792 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2793 "acl_private data is missing");
2796 if (!ac->am_system && !ac->am_administrator) {
2797 ret = acl_search_update_confidential_attrs(ac, data);
2798 if (ret != LDB_SUCCESS) {
2802 if (data->confidential_attrs != NULL) {
2803 down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
2804 if (down_tree == NULL) {
2805 return ldb_oom(ldb);
2808 for (i = 0; data->confidential_attrs[i]; i++) {
2809 ldb_parse_tree_attr_replace(down_tree,
2810 data->confidential_attrs[i],
2811 "kludgeACLredactedattribute");
2816 ret = ldb_build_search_req_ex(&down_req,
2818 req->op.search.base,
2819 req->op.search.scope,
2821 req->op.search.attrs,
2823 ac, acl_search_callback,
2825 LDB_REQ_SET_LOCATION(down_req);
2826 if (ret != LDB_SUCCESS) {
2829 /* perform the search */
2830 return ldb_next_request(module, down_req);
2833 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
2835 struct ldb_context *ldb = ldb_module_get_ctx(module);
2837 /* allow everybody to read the sequence number */
2838 if (strcmp(req->op.extended.oid,
2839 LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
2840 return ldb_next_request(module, req);
2843 if (dsdb_have_system_access(module,
2845 SYSTEM_CONTROL_KEEP_CRITICAL) ||
2846 dsdb_module_am_administrator(module))
2848 return ldb_next_request(module, req);
2850 ldb_asprintf_errstring(ldb,
2852 "attempted database modify not permitted. "
2853 "User %s is not SYSTEM or an administrator",
2854 acl_user_name(req, module));
2855 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2859 static const struct ldb_module_ops ldb_acl_module_ops = {
2861 .search = acl_search,
2863 .modify = acl_modify,
2865 .rename = acl_rename,
2866 .extended = acl_extended,
2867 .init_context = acl_module_init
2870 int ldb_acl_module_init(const char *version)
2872 LDB_MODULE_CHECK_VERSION(version);
2873 return ldb_register_module(&ldb_acl_module_ops);