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 ldb_msg_remove_attr(msg
, "allowedAttributesEffective");
451 if (ac
->user_type
== SECURITY_SYSTEM
) {
452 for (i
=0; attr_list
&& attr_list
[i
]; i
++) {
453 ldb_msg_add_string(msg
, "allowedAttributesEffective", attr_list
[i
]);
458 ret
= get_sd_from_ldb_message(mem_ctx
, sd_msg
, &sd
);
460 if (ret
!= LDB_SUCCESS
) {
463 ret
= get_dom_sid_from_ldb_message(mem_ctx
, sd_msg
, &sid
);
465 if (ret
!= LDB_SUCCESS
) {
468 for (i
=0; attr_list
&& attr_list
[i
]; i
++) {
469 struct dsdb_attribute
*attr
= dsdb_attribute_by_lDAPDisplayName(schema
,
472 return LDB_ERR_OPERATIONS_ERROR
;
474 /* remove constructed attributes */
475 if (attr
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
477 || (attr
->linkID
!= 0 && attr
->linkID
% 2 != 0 )) {
480 ret
= acl_check_access_on_attribute(module
,
486 if (ret
== LDB_SUCCESS
) {
487 ldb_msg_add_string(msg
, "allowedAttributesEffective", attr_list
[i
]);
494 static int acl_childClasses(struct ldb_module
*module
,
495 struct ldb_message
*sd_msg
,
496 struct ldb_message
*msg
,
497 const char *attrName
)
499 struct ldb_message_element
*oc_el
;
500 struct ldb_message_element
*allowedClasses
;
501 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
502 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
503 const struct dsdb_class
*sclass
;
506 /* If we don't have a schema yet, we can't do anything... */
507 if (schema
== NULL
) {
511 /* Must remove any existing attribute, or else confusion reins */
512 ldb_msg_remove_attr(msg
, attrName
);
513 ret
= ldb_msg_add_empty(msg
, attrName
, 0, &allowedClasses
);
514 if (ret
!= LDB_SUCCESS
) {
518 oc_el
= ldb_msg_find_element(sd_msg
, "objectClass");
520 for (i
=0; oc_el
&& i
< oc_el
->num_values
; i
++) {
521 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &oc_el
->values
[i
]);
523 /* We don't know this class? what is going on? */
527 for (j
=0; sclass
->possibleInferiors
&& sclass
->possibleInferiors
[j
]; j
++) {
528 ldb_msg_add_string(msg
, attrName
, sclass
->possibleInferiors
[j
]);
531 if (allowedClasses
->num_values
> 1) {
532 qsort(allowedClasses
->values
,
533 allowedClasses
->num_values
,
534 sizeof(*allowedClasses
->values
),
535 (comparison_fn_t
)data_blob_cmp
);
537 for (i
=1 ; i
< allowedClasses
->num_values
; i
++) {
538 struct ldb_val
*val1
= &allowedClasses
->values
[i
-1];
539 struct ldb_val
*val2
= &allowedClasses
->values
[i
];
540 if (data_blob_cmp(val1
, val2
) == 0) {
541 memmove(val1
, val2
, (allowedClasses
->num_values
- i
) * sizeof(struct ldb_val
));
542 allowedClasses
->num_values
--;
551 static int acl_childClassesEffective(struct ldb_module
*module
,
552 struct ldb_message
*sd_msg
,
553 struct ldb_message
*msg
,
554 struct acl_context
*ac
)
556 struct ldb_message_element
*oc_el
;
557 struct ldb_message_element
*allowedClasses
= NULL
;
558 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
559 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
560 const struct dsdb_class
*sclass
;
561 struct security_descriptor
*sd
;
562 struct dom_sid
*sid
= NULL
;
565 if (ac
->user_type
== SECURITY_SYSTEM
) {
566 return acl_childClasses(module
, sd_msg
, msg
, "allowedChildClassesEffective");
569 /* If we don't have a schema yet, we can't do anything... */
570 if (schema
== NULL
) {
574 /* Must remove any existing attribute, or else confusion reins */
575 ldb_msg_remove_attr(msg
, "allowedChildClassesEffective");
577 oc_el
= ldb_msg_find_element(sd_msg
, "objectClass");
578 ret
= get_sd_from_ldb_message(msg
, sd_msg
, &sd
);
579 if (ret
!= LDB_SUCCESS
) {
582 ret
= get_dom_sid_from_ldb_message(msg
, sd_msg
, &sid
);
584 if (ret
!= LDB_SUCCESS
) {
587 for (i
=0; oc_el
&& i
< oc_el
->num_values
; i
++) {
588 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &oc_el
->values
[i
]);
590 /* We don't know this class? what is going on? */
594 for (j
=0; sclass
->possibleInferiors
&& sclass
->possibleInferiors
[j
]; j
++) {
595 ret
= acl_check_access_on_class(module
,
599 SEC_ADS_CREATE_CHILD
,
600 sclass
->possibleInferiors
[j
]);
601 if (ret
== LDB_SUCCESS
) {
602 ldb_msg_add_string(msg
, "allowedChildClassesEffective",
603 sclass
->possibleInferiors
[j
]);
607 allowedClasses
= ldb_msg_find_element(msg
, "allowedChildClassesEffective");
608 if (!allowedClasses
) {
612 if (allowedClasses
->num_values
> 1) {
613 qsort(allowedClasses
->values
,
614 allowedClasses
->num_values
,
615 sizeof(*allowedClasses
->values
),
616 (comparison_fn_t
)data_blob_cmp
);
617 for (i
=1 ; i
< allowedClasses
->num_values
; i
++) {
618 struct ldb_val
*val1
= &allowedClasses
->values
[i
-1];
619 struct ldb_val
*val2
= &allowedClasses
->values
[i
];
620 if (data_blob_cmp(val1
, val2
) == 0) {
621 memmove(val1
, val2
, (allowedClasses
->num_values
- i
) * sizeof( struct ldb_val
));
622 allowedClasses
->num_values
--;
630 static int acl_sDRightsEffective(struct ldb_module
*module
,
631 struct ldb_message
*sd_msg
,
632 struct ldb_message
*msg
,
633 struct acl_context
*ac
)
635 struct ldb_message_element
*rightsEffective
;
637 struct security_descriptor
*sd
;
638 struct dom_sid
*sid
= NULL
;
641 /* Must remove any existing attribute, or else confusion reins */
642 ldb_msg_remove_attr(msg
, "sDRightsEffective");
643 ret
= ldb_msg_add_empty(msg
, "sDRightsEffective", 0, &rightsEffective
);
644 if (ret
!= LDB_SUCCESS
) {
647 if (ac
->user_type
== SECURITY_SYSTEM
) {
648 flags
= SECINFO_OWNER
| SECINFO_GROUP
| SECINFO_SACL
| SECINFO_DACL
;
651 /* Get the security descriptor from the message */
652 ret
= get_sd_from_ldb_message(msg
, sd_msg
, &sd
);
653 if (ret
!= LDB_SUCCESS
) {
656 ret
= get_dom_sid_from_ldb_message(msg
, sd_msg
, &sid
);
658 if (ret
!= LDB_SUCCESS
) {
661 ret
= acl_check_access_on_attribute(module
,
667 if (ret
== LDB_SUCCESS
) {
668 flags
|= SECINFO_OWNER
| SECINFO_GROUP
;
670 ret
= acl_check_access_on_attribute(module
,
676 if (ret
== LDB_SUCCESS
) {
677 flags
|= SECINFO_DACL
;
679 ret
= acl_check_access_on_attribute(module
,
683 SEC_FLAG_SYSTEM_SECURITY
,
685 if (ret
== LDB_SUCCESS
) {
686 flags
|= SECINFO_SACL
;
689 ldb_msg_add_fmt(msg
, "sDRightsEffective", "%u", flags
);
693 static int acl_add(struct ldb_module
*module
, struct ldb_request
*req
)
696 struct ldb_dn
*parent
= ldb_dn_get_parent(req
, req
->op
.add
.message
->dn
);
697 struct ldb_context
*ldb
;
698 struct ldb_message_element
*oc_el
;
699 const struct GUID
*guid
;
700 struct object_tree
*root
= NULL
;
701 struct object_tree
*new_node
= NULL
;
703 if (what_is_user(module
) == SECURITY_SYSTEM
) {
704 return ldb_next_request(module
, req
);
707 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
708 return ldb_next_request(module
, req
);
710 ldb
= ldb_module_get_ctx(module
);
711 /* Creating an NC. There is probably something we should do here,
712 * but we will establish that later */
713 if ((ldb_dn_compare(req
->op
.add
.message
->dn
, (ldb_get_schema_basedn(ldb
))) == 0) ||
714 (ldb_dn_compare(req
->op
.add
.message
->dn
, (ldb_get_config_basedn(ldb
))) == 0) ||
715 (ldb_dn_compare(req
->op
.add
.message
->dn
, (ldb_get_root_basedn(ldb
))) == 0)) {
716 return ldb_next_request(module
, req
);
719 oc_el
= ldb_msg_find_element(req
->op
.add
.message
, "objectClass");
720 if (!oc_el
|| oc_el
->num_values
== 0) {
721 DEBUG(10,("acl:operation error %s\n", ldb_dn_get_linearized(req
->op
.add
.message
->dn
)));
722 return ldb_module_done(req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
725 guid
= class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb
),
726 (char *)oc_el
->values
[oc_el
->num_values
-1].data
);
728 if (!insert_in_object_tree(req
, guid
, SEC_ADS_CREATE_CHILD
, &root
, &new_node
)) {
729 return LDB_ERR_OPERATIONS_ERROR
;
732 ret
= check_access_on_dn(module
, req
, parent
, SEC_ADS_CREATE_CHILD
, root
);
733 if (ret
!= LDB_SUCCESS
) {
737 return ldb_next_request(module
, req
);
740 static int acl_modify(struct ldb_module
*module
, struct ldb_request
*req
)
743 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
744 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
746 bool modify_sd
= false;
747 const struct GUID
*guid
;
748 uint32_t access_granted
;
749 struct object_tree
*root
= NULL
;
750 struct object_tree
*new_node
= NULL
;
752 struct ldb_result
*acl_res
;
753 struct security_descriptor
*sd
;
754 struct dom_sid
*sid
= NULL
;
755 TALLOC_CTX
*tmp_ctx
= talloc_new(req
);
756 static const char *acl_attrs
[] = {
757 "nTSecurityDescriptor",
763 DEBUG(10, ("ldb:acl_modify: %s\n", req
->op
.mod
.message
->elements
[0].name
));
764 if (what_is_user(module
) == SECURITY_SYSTEM
) {
765 return ldb_next_request(module
, req
);
767 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
768 return ldb_next_request(module
, req
);
770 ret
= ldb_search(ldb
, req
, &acl_res
, req
->op
.mod
.message
->dn
,
771 LDB_SCOPE_BASE
, acl_attrs
, NULL
);
773 if (ret
!= LDB_SUCCESS
) {
777 ret
= get_sd_from_ldb_message(req
, acl_res
->msgs
[0], &sd
);
778 if (ret
!= LDB_SUCCESS
) {
779 DEBUG(10, ("acl_modify: cannot get descriptor\n"));
782 /* Theoretically we pass the check if the object has no sd */
787 guid
= get_oc_guid_from_message(module
,acl_res
->msgs
[0]);
789 DEBUG(10, ("acl_modify: cannot get guid\n"));
793 ret
= get_dom_sid_from_ldb_message(req
, acl_res
->msgs
[0], &sid
);
794 if (ret
!= LDB_SUCCESS
) {
795 return LDB_ERR_OPERATIONS_ERROR
;
798 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_WRITE_PROP
,
800 DEBUG(10, ("acl_modify: cannot add to object tree\n"));
803 for (i
=0; i
< req
->op
.mod
.message
->num_elements
; i
++){
804 const struct dsdb_attribute
*attr
;
805 /* clearTextPassword is not in schema */
806 if (strcmp("clearTextPassword", req
->op
.mod
.message
->elements
[i
].name
) == 0) {
807 attr
= dsdb_attribute_by_lDAPDisplayName(schema
, "unicodePwd");
809 attr
= dsdb_attribute_by_lDAPDisplayName(schema
,
810 req
->op
.mod
.message
->elements
[i
].name
);
812 if (strcmp("nTSecurityDescriptor", req
->op
.mod
.message
->elements
[i
].name
) == 0) {
817 DEBUG(10, ("acl_modify: cannot find attribute %s\n",
818 req
->op
.mod
.message
->elements
[i
].name
));
821 if (!insert_in_object_tree(tmp_ctx
,
822 &attr
->attributeSecurityGUID
, SEC_ADS_WRITE_PROP
,
823 &new_node
, &new_node
)) {
824 DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n"));
828 if (!insert_in_object_tree(tmp_ctx
,
829 &attr
->schemaIDGUID
, SEC_ADS_WRITE_PROP
, &new_node
, &new_node
)) {
830 DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n"));
836 if (root
->num_of_children
> 0) {
837 status
= sec_access_check_ds(sd
, acl_user_token(module
),
843 if (!NT_STATUS_IS_OK(status
)) {
844 DEBUG(10, ("Object %s nas no write property access\n",
845 ldb_dn_get_linearized(req
->op
.mod
.message
->dn
)));
847 acl_user_token(module
),
848 req
->op
.mod
.message
->dn
,
851 talloc_free(tmp_ctx
);
852 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
856 status
= sec_access_check_ds(sd
, acl_user_token(module
),
862 if (!NT_STATUS_IS_OK(status
)) {
863 DEBUG(10, ("Object %s nas no write dacl access\n",
864 ldb_dn_get_linearized(req
->op
.mod
.message
->dn
)));
866 acl_user_token(module
),
867 req
->op
.mod
.message
->dn
,
870 talloc_free(tmp_ctx
);
871 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
875 talloc_free(tmp_ctx
);
876 return ldb_next_request(module
, req
);
878 talloc_free(tmp_ctx
);
879 return LDB_ERR_OPERATIONS_ERROR
;
882 /* similar to the modify for the time being.
883 * We need to concider the special delete tree case, though - TODO */
884 static int acl_delete(struct ldb_module
*module
, struct ldb_request
*req
)
887 struct ldb_dn
*parent
= ldb_dn_get_parent(req
, req
->op
.del
.dn
);
888 struct ldb_context
*ldb
;
890 DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req
->op
.del
.dn
)));
891 if (what_is_user(module
) == SECURITY_SYSTEM
) {
892 return ldb_next_request(module
, req
);
895 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
896 return ldb_next_request(module
, req
);
898 ldb
= ldb_module_get_ctx(module
);
899 /* first check if we have delete object right */
900 ret
= check_access_on_dn(module
, req
, req
->op
.del
.dn
, SEC_STD_DELETE
, NULL
);
901 if (ret
== LDB_SUCCESS
) {
902 return ldb_next_request(module
, req
);
905 /* Nope, we don't have delete object. Lets check if we have delete child on the parent */
906 /* No parent, so check fails */
907 if ((ldb_dn_compare(req
->op
.del
.dn
, (ldb_get_schema_basedn(ldb
))) == 0) ||
908 (ldb_dn_compare(req
->op
.del
.dn
, (ldb_get_config_basedn(ldb
))) == 0) ||
909 (ldb_dn_compare(req
->op
.del
.dn
, (ldb_get_root_basedn(ldb
))) == 0)) {
910 DEBUG(10,("acl:deleting an NC\n"));
911 return ldb_module_done(req
, NULL
, NULL
, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
);
914 ret
= check_access_on_dn(module
, req
, parent
, SEC_ADS_DELETE_CHILD
, NULL
);
915 if (ret
!= LDB_SUCCESS
) {
918 return ldb_next_request(module
, req
);
921 static int acl_rename(struct ldb_module
*module
, struct ldb_request
*req
)
924 struct ldb_dn
*oldparent
= ldb_dn_get_parent(req
, req
->op
.rename
.olddn
);
925 struct ldb_dn
*newparent
= ldb_dn_get_parent(req
, req
->op
.rename
.newdn
);
926 struct ldb_context
*ldb
;
927 struct security_descriptor
*sd
= NULL
;
928 struct dom_sid
*sid
= NULL
;
929 struct ldb_result
*acl_res
;
930 const struct GUID
*guid
;
931 struct object_tree
*root
= NULL
;
932 struct object_tree
*new_node
= NULL
;
933 TALLOC_CTX
*tmp_ctx
= talloc_new(req
);
935 uint32_t access_granted
;
936 static const char *acl_attrs
[] = {
937 "nTSecurityDescriptor",
943 DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
944 if (what_is_user(module
) == SECURITY_SYSTEM
) {
945 return ldb_next_request(module
, req
);
947 if (ldb_dn_is_special(req
->op
.rename
.olddn
)) {
948 return ldb_next_request(module
, req
);
950 ldb
= ldb_module_get_ctx(module
);
952 /* TODO search to include deleted objects */
953 ret
= ldb_search(ldb
, req
, &acl_res
, req
->op
.rename
.olddn
,
954 LDB_SCOPE_BASE
, acl_attrs
, NULL
);
955 /* we sould be able to find the parent */
956 if (ret
!= LDB_SUCCESS
) {
957 DEBUG(10,("acl: failed to find object %s\n",
958 ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
962 guid
= get_oc_guid_from_message(module
,acl_res
->msgs
[0]);
963 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_WRITE_PROP
,
965 return LDB_ERR_OPERATIONS_ERROR
;
968 guid
= attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb
),
970 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_WRITE_PROP
,
971 &new_node
, &new_node
)) {
972 return LDB_ERR_OPERATIONS_ERROR
;
975 ret
= get_sd_from_ldb_message(req
, acl_res
->msgs
[0], &sd
);
977 if (ret
!= LDB_SUCCESS
) {
978 return LDB_ERR_OPERATIONS_ERROR
;
980 /* Theoretically we pass the check if the object has no sd */
984 ret
= get_dom_sid_from_ldb_message(req
, acl_res
->msgs
[0], &sid
);
985 if (ret
!= LDB_SUCCESS
) {
986 return LDB_ERR_OPERATIONS_ERROR
;
989 status
= sec_access_check_ds(sd
, acl_user_token(module
),
995 if (!NT_STATUS_IS_OK(status
)) {
996 DEBUG(10, ("Object %s nas no wp on name\n",
997 ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
999 acl_user_token(module
),
1000 req
->op
.rename
.olddn
,
1003 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
1006 if (ldb_dn_compare(oldparent
, newparent
) == 0) {
1007 /* regular rename, not move, nothing more to do */
1008 return ldb_next_request(module
, req
);
1011 /* What exactly to do in this case? It would fail anyway.. */
1012 if ((ldb_dn_compare(req
->op
.rename
.newdn
, (ldb_get_schema_basedn(ldb
))) == 0) ||
1013 (ldb_dn_compare(req
->op
.rename
.newdn
, (ldb_get_config_basedn(ldb
))) == 0) ||
1014 (ldb_dn_compare(req
->op
.rename
.newdn
, (ldb_get_root_basedn(ldb
))) == 0)) {
1015 DEBUG(10,("acl:moving as an NC\n"));
1016 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
;
1018 /* new parent should have create child */
1019 talloc_free(tmp_ctx
);
1020 tmp_ctx
= talloc_new(req
);
1023 guid
= get_oc_guid_from_message(module
,acl_res
->msgs
[0]);
1025 DEBUG(10,("acl:renamed object has no object class\n"));
1026 return ldb_module_done(req
, NULL
, NULL
, LDB_ERR_OPERATIONS_ERROR
);
1028 if (!insert_in_object_tree(tmp_ctx
, guid
, SEC_ADS_CREATE_CHILD
,
1029 &root
, &new_node
)) {
1030 return LDB_ERR_OPERATIONS_ERROR
;
1032 ret
= check_access_on_dn(module
, req
, newparent
, SEC_ADS_CREATE_CHILD
, root
);
1033 if (ret
!= LDB_SUCCESS
) {
1034 DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
1037 /* do we have delete object on the object? */
1039 status
= sec_access_check_ds(sd
, acl_user_token(module
),
1045 if (NT_STATUS_IS_OK(status
)) {
1046 return ldb_next_request(module
, req
);
1048 /* what about delete child on the current parent */
1049 ret
= check_access_on_dn(module
, req
, oldparent
, SEC_ADS_DELETE_CHILD
, NULL
);
1050 if (ret
!= LDB_SUCCESS
) {
1051 DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
1052 return ldb_module_done(req
, NULL
, NULL
, ret
);
1054 return ldb_next_request(module
, req
);
1057 static int acl_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
1059 struct ldb_context
*ldb
;
1060 struct acl_context
*ac
;
1061 struct acl_private
*data
;
1062 struct ldb_result
*acl_res
;
1063 static const char *acl_attrs
[] = {
1065 "nTSecurityDescriptor",
1071 ac
= talloc_get_type(req
->context
, struct acl_context
);
1072 data
= talloc_get_type(ldb_module_get_private(ac
->module
), struct acl_private
);
1073 ldb
= ldb_module_get_ctx(ac
->module
);
1076 return ldb_module_done(ac
->req
, NULL
, NULL
,
1077 LDB_ERR_OPERATIONS_ERROR
);
1079 if (ares
->error
!= LDB_SUCCESS
) {
1080 return ldb_module_done(ac
->req
, ares
->controls
,
1081 ares
->response
, ares
->error
);
1084 switch (ares
->type
) {
1085 case LDB_REPLY_ENTRY
:
1086 if (ac
->allowedAttributes
1087 || ac
->allowedChildClasses
1088 || ac
->allowedChildClassesEffective
1089 || ac
->allowedAttributesEffective
1090 || ac
->sDRightsEffective
) {
1091 ret
= ldb_search(ldb
, ac
, &acl_res
, ares
->message
->dn
, LDB_SCOPE_BASE
, acl_attrs
, NULL
);
1092 if (ret
!= LDB_SUCCESS
) {
1093 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1095 if (ac
->allowedAttributes
|| ac
->allowedAttributesEffective
) {
1096 ret
= acl_allowedAttributes(ac
->module
, acl_res
->msgs
[0], ares
->message
, ac
);
1097 if (ret
!= LDB_SUCCESS
) {
1098 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1101 if (ac
->allowedChildClasses
) {
1102 ret
= acl_childClasses(ac
->module
, acl_res
->msgs
[0],
1103 ares
->message
, "allowedChildClasses");
1104 if (ret
!= LDB_SUCCESS
) {
1105 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1108 if (ac
->allowedChildClassesEffective
) {
1109 ret
= acl_childClassesEffective(ac
->module
,
1110 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
->sDRightsEffective
) {
1116 ret
= acl_sDRightsEffective(ac
->module
,
1117 acl_res
->msgs
[0], ares
->message
, ac
);
1118 if (ret
!= LDB_SUCCESS
) {
1119 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1123 if (data
&& data
->password_attrs
) {
1124 if (ac
->user_type
!= SECURITY_SYSTEM
) {
1125 for (i
= 0; data
->password_attrs
[i
]; i
++) {
1126 ldb_msg_remove_attr(ares
->message
, data
->password_attrs
[i
]);
1130 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
1132 case LDB_REPLY_REFERRAL
:
1133 return ldb_module_send_referral(ac
->req
, ares
->referral
);
1135 case LDB_REPLY_DONE
:
1136 return ldb_module_done(ac
->req
, ares
->controls
,
1137 ares
->response
, LDB_SUCCESS
);
1143 static int acl_search(struct ldb_module
*module
, struct ldb_request
*req
)
1145 struct ldb_context
*ldb
;
1146 struct acl_context
*ac
;
1147 struct ldb_request
*down_req
;
1148 struct acl_private
*data
;
1151 ldb
= ldb_module_get_ctx(module
);
1153 ac
= talloc_zero(req
, struct acl_context
);
1156 return LDB_ERR_OPERATIONS_ERROR
;
1158 data
= talloc_get_type(ldb_module_get_private(module
), struct acl_private
);
1160 ac
->module
= module
;
1162 ac
->user_type
= what_is_user(module
);
1163 ac
->allowedAttributes
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedAttributes");
1164 ac
->allowedAttributesEffective
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedAttributesEffective");
1165 ac
->allowedChildClasses
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedChildClasses");
1166 ac
->allowedChildClassesEffective
= ldb_attr_in_list(req
->op
.search
.attrs
, "allowedChildClassesEffective");
1167 ac
->sDRightsEffective
= ldb_attr_in_list(req
->op
.search
.attrs
, "sDRightsEffective");
1169 /* replace any attributes in the parse tree that are private,
1170 so we don't allow a search for 'userPassword=penguin',
1171 just as we would not allow that attribute to be returned */
1172 if (ac
->user_type
!= SECURITY_SYSTEM
) {
1173 /* FIXME: We should copy the tree and keep the original unmodified. */
1174 /* remove password attributes */
1175 if (data
&& data
->password_attrs
) {
1176 for (i
= 0; data
->password_attrs
[i
]; i
++) {
1177 ldb_parse_tree_attr_replace(req
->op
.search
.tree
,
1178 data
->password_attrs
[i
],
1179 "kludgeACLredactedattribute");
1183 ret
= ldb_build_search_req_ex(&down_req
,
1185 req
->op
.search
.base
,
1186 req
->op
.search
.scope
,
1187 req
->op
.search
.tree
,
1188 req
->op
.search
.attrs
,
1190 ac
, acl_search_callback
,
1192 if (ret
!= LDB_SUCCESS
) {
1195 /* perform the search */
1196 return ldb_next_request(module
, down_req
);
1199 _PUBLIC_
const struct ldb_module_ops ldb_acl_module_ops
= {
1201 .search
= acl_search
,
1203 .modify
= acl_modify
,
1205 .rename
= acl_rename
,
1206 .init_context
= acl_module_init