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 "librpc/gen_ndr/ndr_security.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "librpc/gen_ndr/ndr_security.h"
41 #include "param/param.h"
43 struct extended_access_check_attribute
{
45 const uint32_t requires_rights
;
50 const char **password_attrs
;
54 struct ldb_module
*module
;
55 struct ldb_request
*req
;
56 enum security_user_level user_type
;
57 bool allowedAttributes
;
58 bool allowedAttributesEffective
;
59 bool allowedChildClasses
;
60 bool allowedChildClassesEffective
;
61 bool sDRightsEffective
;
62 const char * const *attrs
;
65 bool is_root_base_dn(struct ldb_context
*ldb
, struct ldb_dn
*dn_to_check
)
68 struct ldb_dn
*root_base_dn
= ldb_get_root_basedn(ldb
);
69 result
= ldb_dn_compare(root_base_dn
,dn_to_check
);
73 static enum security_user_level
what_is_user(struct ldb_module
*module
)
75 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
76 struct auth_session_info
*session_info
77 = (struct auth_session_info
*)ldb_get_opaque(ldb
, "sessionInfo");
78 return security_session_user_level(session_info
);
81 static struct security_token
*acl_user_token(struct ldb_module
*module
)
83 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
84 struct auth_session_info
*session_info
85 = (struct auth_session_info
*)ldb_get_opaque(ldb
, "sessionInfo");
89 return session_info
->security_token
;
92 static int acl_module_init(struct ldb_module
*module
)
94 struct ldb_context
*ldb
;
95 struct acl_private
*data
;
97 TALLOC_CTX
*mem_ctx
= talloc_new(module
);
98 static const char *attrs
[] = { "passwordAttribute", NULL
};
99 struct ldb_result
*res
;
100 struct ldb_message
*msg
;
101 struct ldb_message_element
*password_attributes
;
103 ldb
= ldb_module_get_ctx(module
);
105 ret
= ldb_mod_register_control(module
, LDB_CONTROL_SD_FLAGS_OID
);
106 if (ret
!= LDB_SUCCESS
) {
107 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
108 "acl_module_init: Unable to register control with rootdse!\n");
109 return LDB_ERR_OPERATIONS_ERROR
;
112 data
= talloc(module
, struct acl_private
);
115 return LDB_ERR_OPERATIONS_ERROR
;
118 data
->password_attrs
= NULL
;
119 data
->acl_perform
= lp_parm_bool(ldb_get_opaque(ldb
, "loadparm"),
120 NULL
, "acl", "perform", false);
121 ldb_module_set_private(module
, data
);
125 return LDB_ERR_OPERATIONS_ERROR
;
128 ret
= ldb_search(ldb
, mem_ctx
, &res
,
129 ldb_dn_new(mem_ctx
, ldb
, "@KLUDGEACL"),
130 LDB_SCOPE_BASE
, attrs
, NULL
);
131 if (ret
!= LDB_SUCCESS
) {
134 if (res
->count
== 0) {
138 if (res
->count
> 1) {
139 talloc_free(mem_ctx
);
140 return LDB_ERR_CONSTRAINT_VIOLATION
;
145 password_attributes
= ldb_msg_find_element(msg
, "passwordAttribute");
146 if (!password_attributes
) {
149 data
->password_attrs
= talloc_array(data
, const char *, password_attributes
->num_values
+ 1);
150 if (!data
->password_attrs
) {
151 talloc_free(mem_ctx
);
153 return LDB_ERR_OPERATIONS_ERROR
;
155 for (i
=0; i
< password_attributes
->num_values
; i
++) {
156 data
->password_attrs
[i
] = (const char *)password_attributes
->values
[i
].data
;
157 talloc_steal(data
->password_attrs
, password_attributes
->values
[i
].data
);
159 data
->password_attrs
[i
] = NULL
;
162 talloc_free(mem_ctx
);
163 return ldb_next_init(module
);
166 static int get_sd_from_ldb_message(TALLOC_CTX
*mem_ctx
,
167 struct ldb_message
*acl_res
,
168 struct security_descriptor
**sd
)
170 struct ldb_message_element
*sd_element
;
171 enum ndr_err_code ndr_err
;
173 sd_element
= ldb_msg_find_element(acl_res
, "nTSecurityDescriptor");
178 *sd
= talloc(mem_ctx
, struct security_descriptor
);
180 return LDB_ERR_OPERATIONS_ERROR
;
182 ndr_err
= ndr_pull_struct_blob(&sd_element
->values
[0], *sd
, NULL
, *sd
,
183 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
186 return LDB_ERR_OPERATIONS_ERROR
;
192 static const struct GUID
*get_oc_guid_from_message(struct ldb_module
*module
,
193 struct ldb_message
*msg
)
195 struct ldb_message_element
*oc_el
;
196 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
198 oc_el
= ldb_msg_find_element(msg
, "objectClass");
203 return class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb
),
204 (char *)oc_el
->values
[oc_el
->num_values
-1].data
);
207 static int get_dom_sid_from_ldb_message(TALLOC_CTX
*mem_ctx
,
208 struct ldb_message
*acl_res
,
209 struct dom_sid
**sid
)
211 struct ldb_message_element
*sid_element
;
212 enum ndr_err_code ndr_err
;
214 sid_element
= ldb_msg_find_element(acl_res
, "objectSid");
219 *sid
= talloc(mem_ctx
, struct dom_sid
);
221 return LDB_ERR_OPERATIONS_ERROR
;
223 ndr_err
= ndr_pull_struct_blob(&sid_element
->values
[0], *sid
, NULL
, *sid
,
224 (ndr_pull_flags_fn_t
)ndr_pull_dom_sid
);
226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
227 return LDB_ERR_OPERATIONS_ERROR
;
234 static void acl_debug(struct security_descriptor
*sd
,
235 struct security_token
*token
,
241 DEBUG(level
, ("Access on %s denied", ldb_dn_get_linearized(dn
)));
243 DEBUG(level
, ("Access on %s granted", ldb_dn_get_linearized(dn
)));
246 DEBUG(level
,("Security context: %s\n",
247 ndr_print_struct_string(0,(ndr_print_fn_t
)ndr_print_security_token
,"", token
)));
248 DEBUG(level
,("Security descriptor: %s\n",
249 ndr_print_struct_string(0,(ndr_print_fn_t
)ndr_print_security_descriptor
,"", sd
)));
252 static int check_access_on_dn(struct ldb_module
*module
,
256 struct object_tree
*tree
)
259 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
260 struct ldb_result
*acl_res
;
261 struct security_descriptor
*sd
= NULL
;
262 struct dom_sid
*sid
= NULL
;
264 uint32_t access_granted
;
265 static const char *acl_attrs
[] = {
266 "nTSecurityDescriptor",
271 ret
= ldb_search(ldb
, mem_ctx
, &acl_res
, dn
, LDB_SCOPE_BASE
, acl_attrs
, NULL
);
272 /* we sould be able to find the parent */
273 if (ret
!= LDB_SUCCESS
) {
274 DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(dn
)));
278 ret
= get_sd_from_ldb_message(mem_ctx
, acl_res
->msgs
[0], &sd
);
279 if (ret
!= LDB_SUCCESS
) {
280 return LDB_ERR_OPERATIONS_ERROR
;
282 /* Theoretically we pass the check if the object has no sd */
286 ret
= get_dom_sid_from_ldb_message(mem_ctx
, acl_res
->msgs
[0], &sid
);
287 if (ret
!= LDB_SUCCESS
) {
288 return LDB_ERR_OPERATIONS_ERROR
;
291 status
= sec_access_check_ds(sd
, acl_user_token(module
),
296 if (!NT_STATUS_IS_OK(status
)) {
298 acl_user_token(module
),
302 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
307 static int acl_check_access_on_attribute(struct ldb_module
*module
,
309 struct security_descriptor
*sd
,
310 struct dom_sid
*rp_sid
,
312 struct dsdb_attribute
*attr
)
316 uint32_t access_granted
;
317 struct object_tree
*root
= NULL
;
318 struct object_tree
*new_node
= NULL
;
319 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
320 struct security_token
*token
= acl_user_token(module
);
322 if (!GUID_all_zero(&attr
->attributeSecurityGUID
)) {
323 if (!insert_in_object_tree(tmp_ctx
,
324 &attr
->attributeSecurityGUID
, access
,
326 DEBUG(10, ("acl_search: cannot add to object tree securityGUID\n"));
330 if (!insert_in_object_tree(tmp_ctx
,
331 &attr
->schemaIDGUID
, access
, &new_node
, &new_node
)) {
332 DEBUG(10, ("acl_search: cannot add to object tree attributeGUID\n"));
337 if (!insert_in_object_tree(tmp_ctx
,
338 &attr
->schemaIDGUID
, access
, &root
, &new_node
)) {
339 DEBUG(10, ("acl_search: cannot add to object tree attributeGUID\n"));
344 status
= sec_access_check_ds(sd
, token
,
349 if (!NT_STATUS_IS_OK(status
)) {
350 ret
= LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
357 return LDB_ERR_OPERATIONS_ERROR
;
360 static int acl_check_access_on_class(struct ldb_module
*module
,
362 struct security_descriptor
*sd
,
363 struct dom_sid
*rp_sid
,
365 const char *class_name
)
368 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
370 uint32_t access_granted
;
371 struct object_tree
*root
= NULL
;
372 struct object_tree
*new_node
= NULL
;
374 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
375 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
376 struct security_token
*token
= acl_user_token(module
);
378 guid
= class_schemaid_guid_by_lDAPDisplayName(schema
, class_name
);
380 DEBUG(10, ("acl_search: cannot find class %s\n",
384 if (!insert_in_object_tree(tmp_ctx
,
387 DEBUG(10, ("acl_search: cannot add to object tree guid\n"));
391 status
= sec_access_check_ds(sd
, token
,
396 if (!NT_STATUS_IS_OK(status
)) {
397 ret
= LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
404 return LDB_ERR_OPERATIONS_ERROR
;
407 static int acl_allowedAttributes(struct ldb_module
*module
,
408 struct ldb_message
*sd_msg
,
409 struct ldb_message
*msg
,
410 struct acl_context
*ac
)
412 struct ldb_message_element
*oc_el
;
413 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
414 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
416 const char **attr_list
;
419 /* If we don't have a schema yet, we can't do anything... */
420 if (schema
== NULL
) {
424 /* Must remove any existing attribute */
425 if (ac
->allowedAttributes
) {
426 ldb_msg_remove_attr(msg
, "allowedAttributes");
429 mem_ctx
= talloc_new(msg
);
432 return LDB_ERR_OPERATIONS_ERROR
;
435 oc_el
= ldb_msg_find_element(sd_msg
, "objectClass");
436 attr_list
= dsdb_full_attribute_list(mem_ctx
, schema
, oc_el
, DSDB_SCHEMA_ALL
);
438 ldb_asprintf_errstring(ldb
, "acl: Failed to get list of attributes");
439 talloc_free(mem_ctx
);
440 return LDB_ERR_OPERATIONS_ERROR
;
442 if (ac
->allowedAttributes
) {
443 for (i
=0; attr_list
&& attr_list
[i
]; i
++) {
444 ldb_msg_add_string(msg
, "allowedAttributes", attr_list
[i
]);
447 if (ac
->allowedAttributesEffective
) {
448 struct security_descriptor
*sd
;
449 struct dom_sid
*sid
= NULL
;
450 struct ldb_control
*as_system
= ldb_request_get_control(ac
->req
,
451 LDB_CONTROL_AS_SYSTEM_OID
);
452 ldb_msg_remove_attr(msg
, "allowedAttributesEffective");
453 if (ac
->user_type
== SECURITY_SYSTEM
|| as_system
) {
454 for (i
=0; attr_list
&& attr_list
[i
]; i
++) {
455 ldb_msg_add_string(msg
, "allowedAttributesEffective", attr_list
[i
]);
460 ret
= get_sd_from_ldb_message(mem_ctx
, sd_msg
, &sd
);
462 if (ret
!= LDB_SUCCESS
) {
465 ret
= get_dom_sid_from_ldb_message(mem_ctx
, sd_msg
, &sid
);
467 if (ret
!= LDB_SUCCESS
) {
470 for (i
=0; attr_list
&& attr_list
[i
]; i
++) {
471 struct dsdb_attribute
*attr
= dsdb_attribute_by_lDAPDisplayName(schema
,
474 return LDB_ERR_OPERATIONS_ERROR
;
476 /* remove constructed attributes */
477 if (attr
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
479 || (attr
->linkID
!= 0 && attr
->linkID
% 2 != 0 )) {
482 ret
= acl_check_access_on_attribute(module
,
488 if (ret
== LDB_SUCCESS
) {
489 ldb_msg_add_string(msg
, "allowedAttributesEffective", attr_list
[i
]);
496 static int acl_childClasses(struct ldb_module
*module
,
497 struct ldb_message
*sd_msg
,
498 struct ldb_message
*msg
,
499 const char *attrName
)
501 struct ldb_message_element
*oc_el
;
502 struct ldb_message_element
*allowedClasses
;
503 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
504 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
505 const struct dsdb_class
*sclass
;
508 /* If we don't have a schema yet, we can't do anything... */
509 if (schema
== NULL
) {
513 /* Must remove any existing attribute, or else confusion reins */
514 ldb_msg_remove_attr(msg
, attrName
);
515 ret
= ldb_msg_add_empty(msg
, attrName
, 0, &allowedClasses
);
516 if (ret
!= LDB_SUCCESS
) {
520 oc_el
= ldb_msg_find_element(sd_msg
, "objectClass");
522 for (i
=0; oc_el
&& i
< oc_el
->num_values
; i
++) {
523 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &oc_el
->values
[i
]);
525 /* We don't know this class? what is going on? */
529 for (j
=0; sclass
->possibleInferiors
&& sclass
->possibleInferiors
[j
]; j
++) {
530 ldb_msg_add_string(msg
, attrName
, sclass
->possibleInferiors
[j
]);
533 if (allowedClasses
->num_values
> 1) {
534 qsort(allowedClasses
->values
,
535 allowedClasses
->num_values
,
536 sizeof(*allowedClasses
->values
),
537 (comparison_fn_t
)data_blob_cmp
);
539 for (i
=1 ; i
< allowedClasses
->num_values
; i
++) {
540 struct ldb_val
*val1
= &allowedClasses
->values
[i
-1];
541 struct ldb_val
*val2
= &allowedClasses
->values
[i
];
542 if (data_blob_cmp(val1
, val2
) == 0) {
543 memmove(val1
, val2
, (allowedClasses
->num_values
- i
) * sizeof(struct ldb_val
));
544 allowedClasses
->num_values
--;
553 static int acl_childClassesEffective(struct ldb_module
*module
,
554 struct ldb_message
*sd_msg
,
555 struct ldb_message
*msg
,
556 struct acl_context
*ac
)
558 struct ldb_message_element
*oc_el
;
559 struct ldb_message_element
*allowedClasses
= NULL
;
560 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
561 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
562 const struct dsdb_class
*sclass
;
563 struct security_descriptor
*sd
;
564 struct ldb_control
*as_system
= ldb_request_get_control(ac
->req
,
565 LDB_CONTROL_AS_SYSTEM_OID
);
566 struct dom_sid
*sid
= NULL
;
569 if (ac
->user_type
== SECURITY_SYSTEM
|| as_system
) {
570 return acl_childClasses(module
, sd_msg
, msg
, "allowedChildClassesEffective");
573 /* If we don't have a schema yet, we can't do anything... */
574 if (schema
== NULL
) {
578 /* Must remove any existing attribute, or else confusion reins */
579 ldb_msg_remove_attr(msg
, "allowedChildClassesEffective");
581 oc_el
= ldb_msg_find_element(sd_msg
, "objectClass");
582 ret
= get_sd_from_ldb_message(msg
, sd_msg
, &sd
);
583 if (ret
!= LDB_SUCCESS
) {
586 ret
= get_dom_sid_from_ldb_message(msg
, sd_msg
, &sid
);
588 if (ret
!= LDB_SUCCESS
) {
591 for (i
=0; oc_el
&& i
< oc_el
->num_values
; i
++) {
592 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &oc_el
->values
[i
]);
594 /* We don't know this class? what is going on? */
598 for (j
=0; sclass
->possibleInferiors
&& sclass
->possibleInferiors
[j
]; j
++) {
599 ret
= acl_check_access_on_class(module
,
603 SEC_ADS_CREATE_CHILD
,
604 sclass
->possibleInferiors
[j
]);
605 if (ret
== LDB_SUCCESS
) {
606 ldb_msg_add_string(msg
, "allowedChildClassesEffective",
607 sclass
->possibleInferiors
[j
]);
611 allowedClasses
= ldb_msg_find_element(msg
, "allowedChildClassesEffective");
612 if (!allowedClasses
) {
616 if (allowedClasses
->num_values
> 1) {
617 qsort(allowedClasses
->values
,
618 allowedClasses
->num_values
,
619 sizeof(*allowedClasses
->values
),
620 (comparison_fn_t
)data_blob_cmp
);
621 for (i
=1 ; i
< allowedClasses
->num_values
; i
++) {
622 struct ldb_val
*val1
= &allowedClasses
->values
[i
-1];
623 struct ldb_val
*val2
= &allowedClasses
->values
[i
];
624 if (data_blob_cmp(val1
, val2
) == 0) {
625 memmove(val1
, val2
, (allowedClasses
->num_values
- i
) * sizeof( struct ldb_val
));
626 allowedClasses
->num_values
--;
634 static int acl_sDRightsEffective(struct ldb_module
*module
,
635 struct ldb_message
*sd_msg
,
636 struct ldb_message
*msg
,
637 struct acl_context
*ac
)
639 struct ldb_message_element
*rightsEffective
;
641 struct security_descriptor
*sd
;
642 struct ldb_control
*as_system
= ldb_request_get_control(ac
->req
,
643 LDB_CONTROL_AS_SYSTEM_OID
);
644 struct dom_sid
*sid
= NULL
;
647 /* Must remove any existing attribute, or else confusion reins */
648 ldb_msg_remove_attr(msg
, "sDRightsEffective");
649 ret
= ldb_msg_add_empty(msg
, "sDRightsEffective", 0, &rightsEffective
);
650 if (ret
!= LDB_SUCCESS
) {
653 if (ac
->user_type
== SECURITY_SYSTEM
|| as_system
) {
654 flags
= SECINFO_OWNER
| SECINFO_GROUP
| SECINFO_SACL
| SECINFO_DACL
;
657 /* Get the security descriptor from the message */
658 ret
= get_sd_from_ldb_message(msg
, sd_msg
, &sd
);
659 if (ret
!= LDB_SUCCESS
) {
662 ret
= get_dom_sid_from_ldb_message(msg
, sd_msg
, &sid
);
664 if (ret
!= LDB_SUCCESS
) {
667 ret
= acl_check_access_on_attribute(module
,
673 if (ret
== LDB_SUCCESS
) {
674 flags
|= SECINFO_OWNER
| SECINFO_GROUP
;
676 ret
= acl_check_access_on_attribute(module
,
682 if (ret
== LDB_SUCCESS
) {
683 flags
|= SECINFO_DACL
;
685 ret
= acl_check_access_on_attribute(module
,
689 SEC_FLAG_SYSTEM_SECURITY
,
691 if (ret
== LDB_SUCCESS
) {
692 flags
|= SECINFO_SACL
;
695 ldb_msg_add_fmt(msg
, "sDRightsEffective", "%u", flags
);
699 static int acl_add(struct ldb_module
*module
, struct ldb_request
*req
)
702 struct ldb_dn
*parent
= ldb_dn_get_parent(req
, req
->op
.add
.message
->dn
);
703 struct ldb_context
*ldb
;
704 struct ldb_message_element
*oc_el
;
705 const struct GUID
*guid
;
706 struct object_tree
*root
= NULL
;
707 struct object_tree
*new_node
= NULL
;
708 struct ldb_control
*as_system
= ldb_request_get_control(req
, LDB_CONTROL_AS_SYSTEM_OID
);
710 if (what_is_user(module
) == SECURITY_SYSTEM
|| as_system
) {
711 return ldb_next_request(module
, req
);
714 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
715 return ldb_next_request(module
, req
);
717 ldb
= ldb_module_get_ctx(module
);
718 /* Creating an NC. There is probably something we should do here,
719 * but we will establish that later */
720 if ((ldb_dn_compare(req
->op
.add
.message
->dn
, (ldb_get_schema_basedn(ldb
))) == 0) ||
721 (ldb_dn_compare(req
->op
.add
.message
->dn
, (ldb_get_config_basedn(ldb
))) == 0) ||
722 (ldb_dn_compare(req
->op
.add
.message
->dn
, (ldb_get_root_basedn(ldb
))) == 0)) {
723 return ldb_next_request(module
, req
);
726 oc_el
= ldb_msg_find_element(req
->op
.add
.message
, "objectClass");
727 if (!oc_el
|| oc_el
->num_values
== 0) {
728 DEBUG(10,("acl:operation error %s\n", ldb_dn_get_linearized(req
->op
.add
.message
->dn
)));
729 return ldb_module_done(req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
732 guid
= class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb
),
733 (char *)oc_el
->values
[oc_el
->num_values
-1].data
);
735 if (!insert_in_object_tree(req
, guid
, SEC_ADS_CREATE_CHILD
, &root
, &new_node
)) {
736 return LDB_ERR_OPERATIONS_ERROR
;
739 ret
= check_access_on_dn(module
, req
, parent
, SEC_ADS_CREATE_CHILD
, root
);
740 if (ret
!= LDB_SUCCESS
) {
744 return ldb_next_request(module
, req
);
747 static int acl_modify(struct ldb_module
*module
, struct ldb_request
*req
)
750 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
751 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
753 bool modify_sd
= false;
754 const struct GUID
*guid
;
755 uint32_t access_granted
;
756 struct object_tree
*root
= NULL
;
757 struct object_tree
*new_node
= NULL
;
759 struct ldb_result
*acl_res
;
760 struct security_descriptor
*sd
;
761 struct dom_sid
*sid
= NULL
;
762 struct ldb_control
*as_system
= ldb_request_get_control(req
, LDB_CONTROL_AS_SYSTEM_OID
);
763 TALLOC_CTX
*tmp_ctx
= talloc_new(req
);
764 static const char *acl_attrs
[] = {
765 "nTSecurityDescriptor",
771 /* Don't print this debug statement if elements[0].name is going to be NULL */
772 if(req
->op
.mod
.message
->num_elements
> 0)
774 DEBUG(10, ("ldb:acl_modify: %s\n", req
->op
.mod
.message
->elements
[0].name
));
776 if (what_is_user(module
) == SECURITY_SYSTEM
|| as_system
) {
777 return ldb_next_request(module
, req
);
779 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
780 return ldb_next_request(module
, req
);
782 ret
= ldb_search(ldb
, req
, &acl_res
, req
->op
.mod
.message
->dn
,
783 LDB_SCOPE_BASE
, acl_attrs
, NULL
);
785 if (ret
!= LDB_SUCCESS
) {
789 ret
= get_sd_from_ldb_message(req
, acl_res
->msgs
[0], &sd
);
790 if (ret
!= LDB_SUCCESS
) {
791 DEBUG(10, ("acl_modify: cannot get descriptor\n"));
794 /* Theoretically we pass the check if the object has no sd */
799 guid
= get_oc_guid_from_message(module
,acl_res
->msgs
[0]);
801 DEBUG(10, ("acl_modify: cannot get guid\n"));
805 ret
= get_dom_sid_from_ldb_message(req
, acl_res
->msgs
[0], &sid
);
806 if (ret
!= LDB_SUCCESS
) {
807 return LDB_ERR_OPERATIONS_ERROR
;
810 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_WRITE_PROP
,
812 DEBUG(10, ("acl_modify: cannot add to object tree\n"));
815 for (i
=0; i
< req
->op
.mod
.message
->num_elements
; i
++){
816 const struct dsdb_attribute
*attr
;
817 /* clearTextPassword is not in schema */
818 if (strcmp("clearTextPassword", req
->op
.mod
.message
->elements
[i
].name
) == 0) {
819 attr
= dsdb_attribute_by_lDAPDisplayName(schema
, "unicodePwd");
821 attr
= dsdb_attribute_by_lDAPDisplayName(schema
,
822 req
->op
.mod
.message
->elements
[i
].name
);
824 if (strcmp("nTSecurityDescriptor", req
->op
.mod
.message
->elements
[i
].name
) == 0) {
829 DEBUG(10, ("acl_modify: cannot find attribute %s\n",
830 req
->op
.mod
.message
->elements
[i
].name
));
833 if (!insert_in_object_tree(tmp_ctx
,
834 &attr
->attributeSecurityGUID
, SEC_ADS_WRITE_PROP
,
835 &new_node
, &new_node
)) {
836 DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n"));
840 if (!insert_in_object_tree(tmp_ctx
,
841 &attr
->schemaIDGUID
, SEC_ADS_WRITE_PROP
, &new_node
, &new_node
)) {
842 DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n"));
848 if (root
->num_of_children
> 0) {
849 status
= sec_access_check_ds(sd
, acl_user_token(module
),
855 if (!NT_STATUS_IS_OK(status
)) {
856 DEBUG(10, ("Object %s nas no write property access\n",
857 ldb_dn_get_linearized(req
->op
.mod
.message
->dn
)));
859 acl_user_token(module
),
860 req
->op
.mod
.message
->dn
,
863 talloc_free(tmp_ctx
);
864 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
868 status
= sec_access_check_ds(sd
, acl_user_token(module
),
874 if (!NT_STATUS_IS_OK(status
)) {
875 DEBUG(10, ("Object %s nas no write dacl access\n",
876 ldb_dn_get_linearized(req
->op
.mod
.message
->dn
)));
878 acl_user_token(module
),
879 req
->op
.mod
.message
->dn
,
882 talloc_free(tmp_ctx
);
883 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
887 talloc_free(tmp_ctx
);
888 return ldb_next_request(module
, req
);
890 talloc_free(tmp_ctx
);
891 return LDB_ERR_OPERATIONS_ERROR
;
894 /* similar to the modify for the time being.
895 * We need to concider the special delete tree case, though - TODO */
896 static int acl_delete(struct ldb_module
*module
, struct ldb_request
*req
)
899 struct ldb_dn
*parent
= ldb_dn_get_parent(req
, req
->op
.del
.dn
);
900 struct ldb_context
*ldb
;
901 struct ldb_control
*as_system
= ldb_request_get_control(req
, LDB_CONTROL_AS_SYSTEM_OID
);
903 DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req
->op
.del
.dn
)));
904 if (what_is_user(module
) == SECURITY_SYSTEM
|| as_system
) {
905 return ldb_next_request(module
, req
);
908 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
909 return ldb_next_request(module
, req
);
911 ldb
= ldb_module_get_ctx(module
);
912 /* first check if we have delete object right */
913 ret
= check_access_on_dn(module
, req
, req
->op
.del
.dn
, SEC_STD_DELETE
, NULL
);
914 if (ret
== LDB_SUCCESS
) {
915 return ldb_next_request(module
, req
);
918 /* Nope, we don't have delete object. Lets check if we have delete child on the parent */
919 /* No parent, so check fails */
920 if ((ldb_dn_compare(req
->op
.del
.dn
, (ldb_get_schema_basedn(ldb
))) == 0) ||
921 (ldb_dn_compare(req
->op
.del
.dn
, (ldb_get_config_basedn(ldb
))) == 0) ||
922 (ldb_dn_compare(req
->op
.del
.dn
, (ldb_get_root_basedn(ldb
))) == 0)) {
923 DEBUG(10,("acl:deleting an NC\n"));
924 return ldb_module_done(req
, NULL
, NULL
, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
);
927 ret
= check_access_on_dn(module
, req
, parent
, SEC_ADS_DELETE_CHILD
, NULL
);
928 if (ret
!= LDB_SUCCESS
) {
931 return ldb_next_request(module
, req
);
934 static int acl_rename(struct ldb_module
*module
, struct ldb_request
*req
)
937 struct ldb_dn
*oldparent
= ldb_dn_get_parent(req
, req
->op
.rename
.olddn
);
938 struct ldb_dn
*newparent
= ldb_dn_get_parent(req
, req
->op
.rename
.newdn
);
939 struct ldb_context
*ldb
;
940 struct security_descriptor
*sd
= NULL
;
941 struct dom_sid
*sid
= NULL
;
942 struct ldb_result
*acl_res
;
943 const struct GUID
*guid
;
944 struct object_tree
*root
= NULL
;
945 struct object_tree
*new_node
= NULL
;
946 struct ldb_control
*as_system
= ldb_request_get_control(req
, LDB_CONTROL_AS_SYSTEM_OID
);
947 TALLOC_CTX
*tmp_ctx
= talloc_new(req
);
949 uint32_t access_granted
;
950 static const char *acl_attrs
[] = {
951 "nTSecurityDescriptor",
957 DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
958 if (what_is_user(module
) == SECURITY_SYSTEM
|| as_system
) {
959 return ldb_next_request(module
, req
);
961 if (ldb_dn_is_special(req
->op
.rename
.olddn
)) {
962 return ldb_next_request(module
, req
);
964 ldb
= ldb_module_get_ctx(module
);
966 /* TODO search to include deleted objects */
967 ret
= ldb_search(ldb
, req
, &acl_res
, req
->op
.rename
.olddn
,
968 LDB_SCOPE_BASE
, acl_attrs
, NULL
);
969 /* we sould be able to find the parent */
970 if (ret
!= LDB_SUCCESS
) {
971 DEBUG(10,("acl: failed to find object %s\n",
972 ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
976 guid
= get_oc_guid_from_message(module
,acl_res
->msgs
[0]);
977 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_WRITE_PROP
,
979 return LDB_ERR_OPERATIONS_ERROR
;
982 guid
= attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb
),
984 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_WRITE_PROP
,
985 &new_node
, &new_node
)) {
986 return LDB_ERR_OPERATIONS_ERROR
;
989 ret
= get_sd_from_ldb_message(req
, acl_res
->msgs
[0], &sd
);
991 if (ret
!= LDB_SUCCESS
) {
992 return LDB_ERR_OPERATIONS_ERROR
;
994 /* Theoretically we pass the check if the object has no sd */
998 ret
= get_dom_sid_from_ldb_message(req
, acl_res
->msgs
[0], &sid
);
999 if (ret
!= LDB_SUCCESS
) {
1000 return LDB_ERR_OPERATIONS_ERROR
;
1003 status
= sec_access_check_ds(sd
, acl_user_token(module
),
1009 if (!NT_STATUS_IS_OK(status
)) {
1010 DEBUG(10, ("Object %s nas no wp on name\n",
1011 ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
1013 acl_user_token(module
),
1014 req
->op
.rename
.olddn
,
1017 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
1020 if (ldb_dn_compare(oldparent
, newparent
) == 0) {
1021 /* regular rename, not move, nothing more to do */
1022 return ldb_next_request(module
, req
);
1025 /* What exactly to do in this case? It would fail anyway.. */
1026 if ((ldb_dn_compare(req
->op
.rename
.newdn
, (ldb_get_schema_basedn(ldb
))) == 0) ||
1027 (ldb_dn_compare(req
->op
.rename
.newdn
, (ldb_get_config_basedn(ldb
))) == 0) ||
1028 (ldb_dn_compare(req
->op
.rename
.newdn
, (ldb_get_root_basedn(ldb
))) == 0)) {
1029 DEBUG(10,("acl:moving as an NC\n"));
1030 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
1032 /* new parent should have create child */
1033 talloc_free(tmp_ctx
);
1034 tmp_ctx
= talloc_new(req
);
1037 guid
= get_oc_guid_from_message(module
,acl_res
->msgs
[0]);
1039 DEBUG(10,("acl:renamed object has no object class\n"));
1040 return ldb_module_done(req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
1042 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_CREATE_CHILD
,
1043 &root
, &new_node
)) {
1044 return LDB_ERR_OPERATIONS_ERROR
;
1046 ret
= check_access_on_dn(module
, req
, newparent
, SEC_ADS_CREATE_CHILD
, root
);
1047 if (ret
!= LDB_SUCCESS
) {
1048 DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
1051 /* do we have delete object on the object? */
1053 status
= sec_access_check_ds(sd
, acl_user_token(module
),
1059 if (NT_STATUS_IS_OK(status
)) {
1060 return ldb_next_request(module
, req
);
1062 /* what about delete child on the current parent */
1063 ret
= check_access_on_dn(module
, req
, oldparent
, SEC_ADS_DELETE_CHILD
, NULL
);
1064 if (ret
!= LDB_SUCCESS
) {
1065 DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
1066 return ldb_module_done(req
, NULL
, NULL
, ret
);
1068 return ldb_next_request(module
, req
);
1071 static int acl_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1073 struct ldb_context
*ldb
;
1074 struct acl_context
*ac
;
1075 struct acl_private
*data
;
1076 struct ldb_result
*acl_res
;
1077 static const char *acl_attrs
[] = {
1079 "nTSecurityDescriptor",
1085 ac
= talloc_get_type(req
->context
, struct acl_context
);
1086 data
= talloc_get_type(ldb_module_get_private(ac
->module
), struct acl_private
);
1087 ldb
= ldb_module_get_ctx(ac
->module
);
1090 return ldb_module_done(ac
->req
, NULL
, NULL
,
1091 LDB_ERR_OPERATIONS_ERROR
);
1093 if (ares
->error
!= LDB_SUCCESS
) {
1094 return ldb_module_done(ac
->req
, ares
->controls
,
1095 ares
->response
, ares
->error
);
1098 switch (ares
->type
) {
1099 case LDB_REPLY_ENTRY
:
1100 if (ac
->allowedAttributes
1101 || ac
->allowedChildClasses
1102 || ac
->allowedChildClassesEffective
1103 || ac
->allowedAttributesEffective
1104 || ac
->sDRightsEffective
) {
1105 ret
= ldb_search(ldb
, ac
, &acl_res
, ares
->message
->dn
, LDB_SCOPE_BASE
, acl_attrs
, NULL
);
1106 if (ret
!= LDB_SUCCESS
) {
1107 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1109 if (ac
->allowedAttributes
|| ac
->allowedAttributesEffective
) {
1110 ret
= acl_allowedAttributes(ac
->module
, acl_res
->msgs
[0], ares
->message
, ac
);
1111 if (ret
!= LDB_SUCCESS
) {
1112 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1115 if (ac
->allowedChildClasses
) {
1116 ret
= acl_childClasses(ac
->module
, acl_res
->msgs
[0],
1117 ares
->message
, "allowedChildClasses");
1118 if (ret
!= LDB_SUCCESS
) {
1119 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1122 if (ac
->allowedChildClassesEffective
) {
1123 ret
= acl_childClassesEffective(ac
->module
,
1124 acl_res
->msgs
[0], ares
->message
, ac
);
1125 if (ret
!= LDB_SUCCESS
) {
1126 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1129 if (ac
->sDRightsEffective
) {
1130 ret
= acl_sDRightsEffective(ac
->module
,
1131 acl_res
->msgs
[0], ares
->message
, ac
);
1132 if (ret
!= LDB_SUCCESS
) {
1133 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1137 if (data
&& data
->password_attrs
) {
1138 if (ac
->user_type
!= SECURITY_SYSTEM
) {
1139 for (i
= 0; data
->password_attrs
[i
]; i
++) {
1140 ldb_msg_remove_attr(ares
->message
, data
->password_attrs
[i
]);
1144 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
1146 case LDB_REPLY_REFERRAL
:
1147 return ldb_module_send_referral(ac
->req
, ares
->referral
);
1149 case LDB_REPLY_DONE
:
1150 return ldb_module_done(ac
->req
, ares
->controls
,
1151 ares
->response
, LDB_SUCCESS
);
1157 static int acl_search(struct ldb_module
*module
, struct ldb_request
*req
)
1159 struct ldb_context
*ldb
;
1160 struct acl_context
*ac
;
1161 struct ldb_request
*down_req
;
1162 struct acl_private
*data
;
1165 ldb
= ldb_module_get_ctx(module
);
1167 ac
= talloc_zero(req
, struct acl_context
);
1170 return LDB_ERR_OPERATIONS_ERROR
;
1172 data
= talloc_get_type(ldb_module_get_private(module
), struct acl_private
);
1174 ac
->module
= module
;
1176 ac
->user_type
= what_is_user(module
);
1177 ac
->allowedAttributes
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedAttributes");
1178 ac
->allowedAttributesEffective
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedAttributesEffective");
1179 ac
->allowedChildClasses
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedChildClasses");
1180 ac
->allowedChildClassesEffective
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedChildClassesEffective");
1181 ac
->sDRightsEffective
= ldb_attr_in_list(req
->op
.search
.attrs
, "sDRightsEffective");
1183 /* replace any attributes in the parse tree that are private,
1184 so we don't allow a search for 'userPassword=penguin',
1185 just as we would not allow that attribute to be returned */
1186 if (ac
->user_type
!= SECURITY_SYSTEM
) {
1187 /* FIXME: We should copy the tree and keep the original unmodified. */
1188 /* remove password attributes */
1189 if (data
&& data
->password_attrs
) {
1190 for (i
= 0; data
->password_attrs
[i
]; i
++) {
1191 ldb_parse_tree_attr_replace(req
->op
.search
.tree
,
1192 data
->password_attrs
[i
],
1193 "kludgeACLredactedattribute");
1197 ret
= ldb_build_search_req_ex(&down_req
,
1199 req
->op
.search
.base
,
1200 req
->op
.search
.scope
,
1201 req
->op
.search
.tree
,
1202 req
->op
.search
.attrs
,
1204 ac
, acl_search_callback
,
1206 if (ret
!= LDB_SUCCESS
) {
1209 /* perform the search */
1210 return ldb_next_request(module
, down_req
);
1213 _PUBLIC_
const struct ldb_module_ops ldb_acl_module_ops
= {
1215 .search
= acl_search
,
1217 .modify
= acl_modify
,
1219 .rename
= acl_rename
,
1220 .init_context
= acl_module_init