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 /* acl_search helper */
46 struct ldb_module *module;
47 struct ldb_request *req;
48 struct ldb_request *down_req;
50 /*needed if we have to identify if this is SYSTEM_USER*/
51 enum security_user_level user_type;
53 uint32_t access_needed;
54 struct ldb_dn * dn_to_check;
56 /* set to true when we need to process the request as a SYSTEM_USER, regardless
57 * of the user's actual rights - for example when we need to retrieve the
58 * ntSecurityDescriptor */
60 struct security_token *token;
61 /*needed to identify if we have requested these attributes*/
62 bool nTSecurityDescriptor;
67 struct extended_access_check_attribute {
69 const uint32_t requires_rights;
76 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares);
78 /*FIXME: Perhaps this should go in the .idl file*/
79 #define SEC_GENERIC_ACCESS_NEVER_GRANTED ( 0xFFFFFFFF )
81 /*Contains a part of the attributes - the ones that have predefined required rights*/
82 static const struct extended_access_check_attribute extended_access_checks_table[] =
85 .oa_name = "nTSecurityDescriptor",
86 .requires_rights = SEC_FLAG_SYSTEM_SECURITY & SEC_STD_READ_CONTROL,
90 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
93 .oa_name = "currentValue",
94 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
98 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
101 .oa_name = "unicodePwd",
102 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
105 .oa_name = "ntPwdHistory",
106 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
109 .oa_name = "priorValue",
110 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
113 .oa_name = "supplementalCredentials",
114 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
117 .oa_name = "trustAuthIncoming",
118 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
121 .oa_name = "trustAuthOutgoing",
122 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
125 .oa_name = "ImPwdHistory",
126 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
129 .oa_name = "initialAuthIncoming",
130 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
133 .oa_name = "initialAuthOutgoing",
134 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
137 .oa_name = "msDS-ExecuteScriptPassword",
138 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
142 static NTSTATUS extended_access_check(const char *attribute_name, const int access_rights, uint32_t searchFlags)
145 if (access_rights == SEC_GENERIC_ACCESS_NEVER_GRANTED) {
146 return NT_STATUS_ACCESS_DENIED;
149 /*Check if the attribute is in the table first*/
150 for ( i = 0; extended_access_checks_table[i].oa_name; i++ ) {
151 if (ldb_attr_cmp(extended_access_checks_table[i].oa_name, attribute_name) == 0) {
152 if ((access_rights & extended_access_checks_table[i].requires_rights) == access_rights) {
155 return NT_STATUS_ACCESS_DENIED;
160 /*Check for attribute whose attributeSchema has 0x80 set in searchFlags*/
161 if ((searchFlags & SEARCH_FLAG_CONFIDENTIAL) == SEARCH_FLAG_CONFIDENTIAL) {
162 if (((SEC_ADS_READ_PROP & SEC_ADS_CONTROL_ACCESS) & access_rights) == access_rights) {
165 return NT_STATUS_ACCESS_DENIED;
169 /*Check attributes with *special* behaviour*/
170 if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0 || ldb_attr_cmp("msDS-QuotaUsed", attribute_name) == 0){
173 *(RIGHT_DS_READ_PROPERTY on the Quotas container or
174 *((the client is querying the quota for the security principal it is authenticated as) and
175 *(DS-Query-Self-Quota control access right on the Quotas container))
179 if (ldb_attr_cmp("userPassword", attribute_name) == 0) {
180 /*When the dSHeuristics.fUserPwdSupport flag is false, the requester must be granted RIGHT_DS_READ_PROPERTY.
181 *When the dSHeuristics.fUserPwdSupport flag is true, access is never granted.
185 if (ldb_attr_cmp("sDRightsEffective", attribute_name) == 0) {
186 /*FIXME:3.1.1.4.5.4 in MS-ADTS*/
189 if (ldb_attr_cmp("allowedChildClassesEffective", attribute_name) == 0) {
190 /*FIXME:3.1.1.4.5.5 in MS-ADTS*/
193 if (ldb_attr_cmp("allowedAttributesEffective", attribute_name) == 0) {
194 /*FIXME:3.1.1.4.5.7 in MS-ADTS*/
197 if (ldb_attr_cmp("msDS-Approx-Immed-Subordinates", attribute_name) == 0) {
198 /*FIXME:3.1.1.4.5.15 in MS-ADTS*/
201 if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0) {
202 /*FIXME:3.1.1.4.5.22 in MS-ADTS*/
205 if (ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0 || ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0) {
206 /*The security context of the requester must be granted the following rights on the replPropertyMetaData attribute:
207 *(RIGHT_DS_READ_PROPERTY)or (DS-Replication-Manage-Topology by ON!nTSecurityDescriptor)
211 if (ldb_attr_cmp("msDS-NCReplInboundNeighbors", attribute_name) == 0) {
212 /*The security context of the requester must be granted the following rights on repsFrom:
213 *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
217 if (ldb_attr_cmp("msDS-NCReplOutboundNeighbors", attribute_name) == 0) {
218 /*The security context of the requester must be granted the following rights on repsTo:
219 *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
223 if (ldb_attr_cmp("msDS-NCReplCursors", attribute_name) == 0) {
224 /*The security context of the requester must be granted the following rights on replUpToDateVector: (RIGHT_DS_READ_PROPERTY)
225 *or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
229 if (ldb_attr_cmp("msDS-IsUserCachableAtRodc", attribute_name) == 0) {
230 /*The security context of the requester must be granted
231 *the DS-Replication-Secrets-Synchronize control access right on the root of the default NC.
238 /* Builds an object tree for object specific access checks */
239 static struct object_tree * build_object_tree_form_attr_list(TALLOC_CTX *mem_ctx, /* Todo this context or separate? */
240 struct ldb_context *ldb,
241 const char ** attr_names,
243 const char * object_class,
244 uint32_t init_access)
246 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
247 const struct GUID *oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, object_class);
248 struct object_tree *tree;
254 tree = insert_in_object_tree(mem_ctx, oc_guid, NULL, init_access, NULL);
256 for (i=0; i < num_attrs; i++){
257 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema,attr_names[i]);
259 insert_in_object_tree(mem_ctx,
260 &attribute->schemaIDGUID,
261 &attribute->attributeSecurityGUID,
269 bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check)
272 struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb);
273 result = ldb_dn_compare(root_base_dn,dn_to_check);
277 static int acl_op_callback(struct ldb_request *req, struct ldb_reply *ares)
279 struct acl_context *ac;
281 ac = talloc_get_type(req->context, struct acl_context);
284 return ldb_module_done(ac->req, NULL, NULL,
285 LDB_ERR_OPERATIONS_ERROR);
287 if (ares->error != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 if (ares->type != LDB_REPLY_DONE) {
294 return ldb_module_done(ac->req, NULL, NULL,
295 LDB_ERR_OPERATIONS_ERROR);
298 return ldb_module_done(ac->req, ares->controls,
299 ares->response, ares->error);
303 static int acl_access_check_add(struct ldb_reply *ares,
304 struct acl_context *ac,
305 struct security_descriptor *sd)
307 uint32_t access_granted = 0;
309 struct ldb_dn *parent;
310 struct ldb_dn *grandparent;
311 struct object_tree *tree = NULL;
313 parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
314 grandparent = ldb_dn_get_parent(ac->req, parent);
315 if (ldb_dn_compare(ares->message->dn, grandparent) == 0)
316 status = sec_access_check_ds(sd, ac->token,
320 else if (ldb_dn_compare(ares->message->dn, parent) == 0){
321 struct ldb_message_element *oc_el;
322 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
323 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
326 oc_el = ldb_msg_find_element(ares->message, "objectClass");
327 if (!oc_el || oc_el->num_values == 0)
329 for (i = 0; i < oc_el->num_values; i++){
330 const struct GUID *guid = class_schemaid_guid_by_lDAPDisplayName(schema,
331 oc_el->values[i].data);
332 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
333 tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_CREATE_CHILD,
335 status = sec_access_check_ds(sd, ac->token, SEC_ADS_CREATE_CHILD,&access_granted, tree);
336 if (NT_STATUS_IS_OK(status))
337 ac->sec_result = LDB_SUCCESS;
343 return ac->sec_result;
346 static int acl_access_check_modify(struct ldb_reply *ares, struct acl_context *ac,
347 struct security_descriptor *sd)
349 uint32_t access_granted = 0;
351 struct ldb_dn *parent;
352 struct object_tree *tree = NULL;
354 parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
355 if (ldb_dn_compare(ares->message->dn, parent) == 0)
356 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
357 else if (ldb_dn_compare(ares->message->dn, ac->req->op.add.message->dn) == 0){
358 struct ldb_message_element *oc_el;
359 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
360 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
363 oc_el = ldb_msg_find_element(ares->message, "objectClass");
364 if (!oc_el || oc_el->num_values == 0)
367 guid = class_schemaid_guid_by_lDAPDisplayName(schema,
368 oc_el->values[oc_el->num_values-1].data);
369 tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_WRITE_PROP,
371 for (i=0; i < ac->req->op.mod.message->num_elements; i++){
372 const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
373 ac->req->op.mod.message->elements[i].name);
375 return LDB_ERR_OPERATIONS_ERROR; /* What should we actually return here? */
376 insert_in_object_tree(ac, &attr->schemaIDGUID,
377 &attr->attributeSecurityGUID, ac->access_needed, tree);
379 status = sec_access_check_ds(sd, ac->token, SEC_ADS_WRITE_PROP ,&access_granted, tree);
380 if (!NT_STATUS_IS_OK(status))
381 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
385 return ac->sec_result;
388 static int acl_access_check_rename(struct ldb_reply *ares, struct acl_context *ac,
389 struct security_descriptor *sd)
391 return ac->sec_result;
394 static int acl_access_check_delete(struct ldb_reply *ares, struct acl_context *ac,
395 struct security_descriptor *sd)
397 uint32_t access_granted = 0;
399 struct ldb_dn *parent;
400 struct object_tree *tree = NULL;
402 parent = ldb_dn_get_parent(ac->req, ac->req->op.del.dn);
403 if (ldb_dn_compare(ares->message->dn, parent) == 0){
404 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
405 if (!NT_STATUS_IS_OK(status)){
406 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
407 return ac->sec_result;
409 status = sec_access_check_ds(sd, ac->token, SEC_ADS_DELETE_CHILD,&access_granted, NULL);
410 if (NT_STATUS_IS_OK(status)){
411 ac->sec_result = LDB_SUCCESS;
412 return ac->sec_result;
415 else if (ldb_dn_compare(ares->message->dn, ac->req->op.del.dn) == 0){
416 status = sec_access_check_ds(sd, ac->token, SEC_STD_DELETE, &access_granted, NULL);
417 if (!NT_STATUS_IS_OK(status))
418 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
420 return ac->sec_result;
423 static int acl_access_check_search(struct ldb_reply *ares, struct acl_context *ac,
424 struct security_descriptor *sd)
426 uint32_t access_granted;
428 struct ldb_dn *parent;
430 if (ac->user_type == SECURITY_SYSTEM || ac->user_type == SECURITY_ANONYMOUS) {
431 return LDB_SUCCESS;/*FIXME: we have anonymous access*/
434 parent = ldb_dn_get_parent(ac->req, ac->dn_to_check);
435 ac->sec_result = LDB_SUCCESS;
436 if (ldb_dn_compare(ares->message->dn, parent) == 0) {
437 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
438 if (!NT_STATUS_IS_OK(status)) {
439 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
443 return ac->sec_result;
446 static int acl_perform_access_check(struct ldb_request *req, struct ldb_reply *ares,
447 struct acl_context *ac)
449 struct ldb_message_element *oc_el;
450 struct security_descriptor *sd;
451 enum ndr_err_code ndr_err;
453 oc_el = ldb_msg_find_element(ares->message, "ntSecurityDescriptor");
454 if (!oc_el || oc_el->num_values == 0)
457 sd = talloc(ac, struct security_descriptor);
459 return ldb_module_done(ac->req, ares->controls,
460 ares->response, LDB_ERR_OPERATIONS_ERROR);
462 ndr_err = ndr_pull_struct_blob(&oc_el->values[0], sd, NULL, sd,
463 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err))
466 return ldb_module_done(ac->req, ares->controls,
467 ares->response, LDB_ERR_OPERATIONS_ERROR);
468 switch (ac->req->operation) {
470 return acl_access_check_search(ares, ac, sd);
472 return acl_access_check_add(ares, ac, sd);
474 return acl_access_check_modify(ares, ac, sd);
476 return acl_access_check_delete(ares, ac, sd);
478 return acl_access_check_rename(ares, ac, sd);
480 return ldb_module_done(ac->req, ares->controls,
481 ares->response, LDB_ERR_OPERATIONS_ERROR);
486 static int acl_forward_add(struct ldb_reply *ares,
487 struct acl_context *ac)
489 struct ldb_request *newreq;
490 struct ldb_context *ldb;
493 ldb = ldb_module_get_ctx(ac->module);
494 ret = ldb_build_add_req(&newreq,ldb,
496 ac->req->op.add.message,
501 if (ret != LDB_SUCCESS)
502 return ldb_module_done(ac->req, ares->controls,
503 ares->response, LDB_ERR_OPERATIONS_ERROR);
504 return ldb_next_request(ac->module, newreq);
507 static int acl_forward_modify(struct ldb_reply *ares,
508 struct acl_context *ac)
510 struct ldb_request *newreq;
511 struct ldb_context *ldb;
514 ldb = ldb_module_get_ctx(ac->module);
515 ret = ldb_build_mod_req(&newreq,ldb,
517 ac->req->op.mod.message,
522 if (ret != LDB_SUCCESS)
523 return ldb_module_done(ac->req, ares->controls,
524 ares->response, LDB_ERR_OPERATIONS_ERROR);
525 return ldb_next_request(ac->module, newreq);
528 static int acl_forward_delete(struct ldb_reply *ares,
529 struct acl_context *ac)
531 struct ldb_request *newreq;
532 struct ldb_context *ldb;
535 ldb = ldb_module_get_ctx(ac->module);
536 ret = ldb_build_del_req(&newreq, ldb,
543 if (ret != LDB_SUCCESS)
544 return ldb_module_done(ac->req, ares->controls,
545 ares->response, LDB_ERR_OPERATIONS_ERROR);
546 return ldb_next_request(ac->module, newreq);
549 static int acl_forward_rename(struct ldb_reply *ares,
550 struct acl_context *ac)
555 static int acl_forward_search(struct acl_context *ac)
558 const char * const *attrs;
559 struct ldb_control *sd_control;
560 struct ldb_control **sd_saved_controls;
561 struct ldb_context *ldb;
562 struct ldb_request *newreq;
564 ldb = ldb_module_get_ctx(ac->module);
565 attrs = ac->req->op.search.attrs;
567 ac->nTSecurityDescriptor = false;
568 ac->objectClass = false;
569 if (!ldb_attr_in_list(ac->req->op.search.attrs, "nTSecurityDescriptor")) {
570 attrs = ldb_attr_list_copy_add(ac, attrs, "nTSecurityDescriptor");
571 ac->nTSecurityDescriptor = true;
573 if (!ldb_attr_in_list(ac->req->op.search.attrs, "objectClass")) {
574 attrs = ldb_attr_list_copy_add(ac, attrs, "objectClass");
575 ac->objectClass = true;
578 ret = ldb_build_search_req_ex(&newreq,ldb,
580 ac->req->op.search.base,
581 ac->req->op.search.scope,
582 ac->req->op.search.tree,
585 ac, acl_search_callback,
587 if (ret != LDB_SUCCESS) {
588 return LDB_ERR_OPERATIONS_ERROR;
590 /* check if there's an SD_FLAGS control */
591 sd_control = ldb_request_get_control(newreq, LDB_CONTROL_SD_FLAGS_OID);
593 /* save it locally and remove it from the list */
594 /* we do not need to replace them later as we
595 * are keeping the original req intact */
596 if (!save_controls(sd_control, newreq, &sd_saved_controls)) {
597 return LDB_ERR_OPERATIONS_ERROR;
600 return ldb_next_request(ac->module, newreq);
603 static int acl_forward_request(struct ldb_reply *ares,
604 struct acl_context *ac)
606 switch (ac->req->operation) {
608 return acl_forward_search(ac);
610 return acl_forward_add(ares,ac);
612 return acl_forward_modify(ares,ac);
614 return acl_forward_delete(ares,ac);
616 return acl_forward_rename(ares,ac);
618 return ldb_module_done(ac->req, ares->controls,
619 ares->response, LDB_ERR_OPERATIONS_ERROR);
624 static int acl_visible_callback(struct ldb_request *req, struct ldb_reply *ares)
626 struct acl_context *ac;
628 ac = talloc_get_type(req->context, struct acl_context);
631 return ldb_module_done(ac->req, NULL, NULL,
632 LDB_ERR_OPERATIONS_ERROR);
635 if (ares->error != LDB_SUCCESS) {
636 return ldb_module_done(ac->req, ares->controls,
637 ares->response, ares->error);
640 switch (ares->type) {
641 case LDB_REPLY_ENTRY:
642 return acl_perform_access_check(req, ares, ac);
643 case LDB_REPLY_REFERRAL:
644 return ldb_module_send_referral(ac->req, ares->referral); /* what to do here actually? */
646 if (ac->sec_result != LDB_SUCCESS) {
647 return ldb_module_done(ac->req, ares->controls,
648 ares->response, ac->sec_result);
650 return acl_forward_request(ares,ac);
657 static enum security_user_level what_is_user(struct ldb_module *module)
659 struct ldb_context *ldb = ldb_module_get_ctx(module);
660 struct auth_session_info *session_info
661 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
662 return security_session_user_level(session_info);
665 static struct security_token * user_token(struct ldb_module *module)
667 struct ldb_context *ldb = ldb_module_get_ctx(module);
668 struct auth_session_info *session_info
669 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
673 return session_info->security_token;
677 static int make_req_access_check(struct ldb_module *module, struct ldb_request *req,
678 struct acl_context *ac, const char *filter)
680 struct ldb_context *ldb;
682 const char **attrs = talloc_array(ac, const char *, 3);
683 struct ldb_parse_tree *tree = ldb_parse_tree(req, filter);
685 attrs[0] = talloc_strdup(attrs, "ntSecurityDescriptor");
686 attrs[1] = talloc_strdup(attrs, "objectClass");
689 ldb = ldb_module_get_ctx(module);
690 ret = ldb_build_search_req_ex(&ac->down_req,
697 ac, acl_visible_callback,
702 static const char *user_name(TALLOC_CTX *mem_ctx, struct ldb_module *module)
704 struct ldb_context *ldb = ldb_module_get_ctx(module);
705 struct auth_session_info *session_info
706 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
708 return "UNKNOWN (NULL)";
711 return talloc_asprintf(mem_ctx, "%s\\%s",
712 session_info->server_info->domain_name,
713 session_info->server_info->account_name);
716 static int acl_module_init(struct ldb_module *module)
718 struct ldb_context *ldb;
719 struct acl_private *data;
722 ldb = ldb_module_get_ctx(module);
724 ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
725 if (ret != LDB_SUCCESS) {
726 ldb_debug(ldb, LDB_DEBUG_ERROR,
727 "acl_module_init: Unable to register control with rootdse!\n");
728 return LDB_ERR_OPERATIONS_ERROR;
731 data = talloc(module, struct acl_private);
732 data->perform_check = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
733 NULL, "acl", "perform", false);
734 ldb_module_set_private(module, data);
736 return ldb_next_init(module);
739 static int acl_add(struct ldb_module *module, struct ldb_request *req)
742 struct acl_context *ac;
743 struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.add.message->dn);
745 struct ldb_context *ldb;
746 struct acl_private *data;
748 ldb = ldb_module_get_ctx(module);
749 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
751 if (!data->perform_check)
752 return ldb_next_request(module, req);
754 ac = talloc(req, struct acl_context);
756 return LDB_ERR_OPERATIONS_ERROR;
759 if (what_is_user(module) == SECURITY_SYSTEM)
760 return ldb_next_request(module, req);
764 ac->ignore_security = true;
765 ac->dn_to_check = ldb_dn_get_parent(req, parent);
766 ac->token = user_token(module);
767 ac->user_type = what_is_user(module);
768 ac->sec_result = LDB_SUCCESS;
769 if (!is_root_base_dn(ldb, req->op.add.message->dn) && parent && !is_root_base_dn(ldb, parent)){
770 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
771 ldb_dn_get_component_name(parent,0),
772 ldb_dn_get_component_val(parent,0)->data,
773 ldb_dn_get_component_name(ac->dn_to_check,0),
774 ldb_dn_get_component_val(ac->dn_to_check,0)->data);
776 ret = make_req_access_check(module, req, ac, filter);
777 if (ret != LDB_SUCCESS){
780 return ldb_next_request(module, ac->down_req);
782 return ldb_next_request(module, req);
785 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
788 struct acl_context *ac;
789 struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.mod.message->dn);
791 struct ldb_context *ldb;
792 struct acl_private *data;
794 ldb = ldb_module_get_ctx(module);
795 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
797 if (!data->perform_check)
798 return ldb_next_request(module, req);
800 ac = talloc(req, struct acl_context);
802 return LDB_ERR_OPERATIONS_ERROR;
805 /* if (what_is_user(module) == SECURITY_SYSTEM) */
806 return ldb_next_request(module, req);
810 ac->ignore_security = true;
811 ac->dn_to_check = req->op.mod.message->dn;
812 ac->token = user_token(module);
813 ac->user_type = what_is_user(module);
814 ac->sec_result = LDB_SUCCESS;
815 if (!is_root_base_dn(ldb, req->op.mod.message->dn) && parent && !is_root_base_dn(ldb, parent)){
816 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
817 ldb_dn_get_component_name(parent,0),
818 ldb_dn_get_component_val(parent,0)->data,
819 ldb_dn_get_component_name(req->op.mod.message->dn,0),
820 ldb_dn_get_component_val(req->op.mod.message->dn,0)->data);
822 ret = make_req_access_check(module, req, ac, filter);
823 if (ret != LDB_SUCCESS){
826 return ldb_next_request(module, ac->down_req);
828 return ldb_next_request(module, req);
831 /* similar to the modify for the time being.
832 * We need to concider the special delete tree case, though - TODO */
833 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
836 struct acl_context *ac;
837 struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.del.dn);
839 struct ldb_context *ldb;
840 struct acl_private *data;
842 ldb = ldb_module_get_ctx(module);
843 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
845 if (!data->perform_check)
846 return ldb_next_request(module, req);
848 ac = talloc(req, struct acl_context);
850 return LDB_ERR_OPERATIONS_ERROR;
853 if (ac->user_type == SECURITY_SYSTEM)
854 return ldb_next_request(module, req);
858 ac->ignore_security = true;
859 ac->dn_to_check = req->op.del.dn;
860 ac->token = user_token(module);
861 ac->user_type = what_is_user(module);
862 ac->sec_result = LDB_SUCCESS;
864 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
865 ldb_dn_get_component_name(parent,0),
866 ldb_dn_get_component_val(parent,0)->data,
867 ldb_dn_get_component_name(req->op.del.dn,0),
868 ldb_dn_get_component_val(req->op.del.dn,0)->data);
869 ret = make_req_access_check(module, req, ac, filter);
871 if (ret != LDB_SUCCESS){
874 return ldb_next_request(module, ac->down_req);
877 return ldb_next_request(module, req);
880 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
882 struct ldb_dn *source_parent;
883 struct ldb_dn *dest_parent;
885 struct acl_context *ac;
887 struct ldb_context *ldb;
888 struct acl_private *data;
890 ldb = ldb_module_get_ctx(module);
891 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
893 if (!data->perform_check)
894 return ldb_next_request(module, req);
896 ac = talloc(req, struct acl_context);
898 return LDB_ERR_OPERATIONS_ERROR;
901 if (ac->user_type == SECURITY_SYSTEM)
902 return ldb_next_request(module, req);
906 ac->ignore_security = true;
907 ac->token = user_token(module);
908 ac->user_type = what_is_user(module);
909 ac->sec_result = LDB_SUCCESS;
911 /* We need to know if it is a simple rename or a move operation */
912 source_parent = ldb_dn_get_parent(req, req->op.rename.olddn);
913 dest_parent = ldb_dn_get_parent(req, req->op.rename.newdn);
915 if (ldb_dn_compare(source_parent, dest_parent) == 0){
916 /*Not a move, just rename*/
917 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
918 ldb_dn_get_component_name(dest_parent,0),
919 ldb_dn_get_component_val(dest_parent,0)->data,
920 ldb_dn_get_component_name(req->op.rename.olddn,0),
921 ldb_dn_get_component_val(req->op.rename.olddn,0)->data);
924 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
925 ldb_dn_get_component_name(dest_parent,0),
926 ldb_dn_get_component_val(dest_parent,0)->data,
927 ldb_dn_get_component_name(source_parent,0),
928 ldb_dn_get_component_val(source_parent,0)->data);
931 ret = make_req_access_check(module, req, ac, filter);
933 if (ret != LDB_SUCCESS){
936 return ldb_next_request(module, ac->down_req);
939 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
941 struct ldb_context *ldb;
942 struct acl_context *ac;
943 struct security_descriptor *sd;
944 uint32_t searchFlags;
945 uint32_t access_mask;
946 struct object_tree *ot;
949 struct ldb_message_element *element_security_descriptor;
950 struct ldb_message_element *element_object_class;
951 const struct dsdb_attribute *attr;
952 const struct dsdb_schema *schema;
953 struct GUID *oc_guid;
955 ac = talloc_get_type(req->context, struct acl_context);
956 ldb = ldb_module_get_ctx(ac->module);
957 schema = dsdb_get_schema(ldb);
959 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
961 if (ares->error != LDB_SUCCESS) {
962 return ldb_module_done(ac->req, ares->controls, ares->response, ares->error);
965 switch (ares->type) {
966 case LDB_REPLY_ENTRY:
967 switch (ac->user_type) {
968 case SECURITY_SYSTEM:
969 case SECURITY_ANONYMOUS:/*FIXME: should we let anonymous have system access*/
974 * 0. If we do not have nTSecurityDescriptor, we do not have an object in the response,
975 * so check the parent dn.
976 * 1. Call sec_access_check on empty tree
977 * 2. For each attribute call extended_access_check
978 * 3. For each attribute call build_object_tree_form_attr_list and then check with sec_access_check
981 element_security_descriptor = ldb_msg_find_element(ares->message, "nTSecurityDescriptor");
982 element_object_class = ldb_msg_find_element(ares->message, "objectClass");
983 if (!element_security_descriptor || !element_object_class)
986 sd = talloc(ldb, struct security_descriptor);
988 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
990 if(!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&element_security_descriptor->values[0],
994 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
995 DEBUG(0, ("acl_search_callback: Error parsing security descriptor\n"));
996 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
999 oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, element_object_class->values[0].data);
1000 for (i=0; i<ares->message->num_elements; i++) {
1001 attr = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name);
1003 searchFlags = attr->searchFlags;
1008 /*status = extended_access_check(ares->message->elements[i].name, access_mask, searchFlags); */ /* Todo FIXME */
1009 ac->access_needed = SEC_ADS_READ_PROP;
1010 if (NT_STATUS_IS_OK(status)) {
1011 ot = insert_in_object_tree(req, oc_guid, NULL, ac->access_needed, NULL);
1013 insert_in_object_tree(req,
1014 &attr->schemaIDGUID,
1015 &attr->attributeSecurityGUID,
1019 status = sec_access_check_ds(sd,
1025 if (NT_STATUS_IS_OK(status)) {
1029 ldb_msg_remove_attr(ares->message, ares->message->elements[i].name);
1033 if (ac->nTSecurityDescriptor) {
1034 ldb_msg_remove_attr(ares->message, "nTSecurityDescriptor");
1035 } else if (ac->objectClass) {
1036 ldb_msg_remove_attr(ares->message, "objectClass");
1039 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1040 case LDB_REPLY_REFERRAL:
1041 return ldb_module_send_referral(ac->req, ares->referral);
1043 case LDB_REPLY_DONE:
1044 return ldb_module_done(ac->req, ares->controls,ares->response, LDB_SUCCESS);
1050 static int acl_search(struct ldb_module *module, struct ldb_request *req)
1053 struct ldb_context *ldb;
1054 struct acl_context *ac;
1056 struct ldb_control *sd_control;
1057 struct ldb_control **sd_saved_controls;
1058 struct ldb_dn * parent;
1059 struct acl_private *data;
1061 ldb = ldb_module_get_ctx(module);
1062 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1064 if (!data || !data->perform_check)
1065 return ldb_next_request(module, req);
1067 if (what_is_user(module) == SECURITY_SYSTEM)
1068 return ldb_next_request(module, req);
1070 ac = talloc_get_type(req->context, struct acl_context);
1072 ac = talloc(req, struct acl_context);
1075 return LDB_ERR_OPERATIONS_ERROR;
1077 ac->module = module;
1079 ac->ignore_security = false;
1080 ac->user_type = what_is_user(module);
1081 ac->token = user_token(module);
1082 ac->dn_to_check = req->op.search.base;
1083 ac->sec_result = LDB_SUCCESS;
1085 attrs = talloc_array(ac, const char*, 2);
1086 attrs[0] = talloc_strdup(attrs, "nTSecurityDescriptor");
1088 parent = ldb_dn_get_parent(req, ac->dn_to_check);
1089 if (!is_root_base_dn(ldb, req->op.search.base) && parent && !is_root_base_dn(ldb, parent)) {
1090 /*we have parent so check for visibility*/
1091 ret = ldb_build_search_req(&ac->down_req,
1098 ac, acl_visible_callback,
1100 if (ret != LDB_SUCCESS) {
1103 return ldb_next_request(module, ac->down_req);
1105 return acl_forward_search(ac);
1109 return ldb_next_request(module, req);
1112 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
1114 struct ldb_context *ldb = ldb_module_get_ctx(module);
1115 enum security_user_level user_type;
1116 struct acl_private *data;
1118 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1120 if (!data->perform_check)
1121 return ldb_next_request(module, req);
1123 /* allow everybody to read the sequence number */
1124 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1125 return ldb_next_request(module, req);
1128 user_type = what_is_user(module);
1129 switch (user_type) {
1130 case SECURITY_SYSTEM:
1131 case SECURITY_ADMINISTRATOR:
1132 return ldb_next_request(module, req);
1134 ldb_asprintf_errstring(ldb,
1135 "acl_extended: attempted database modify not permitted."
1136 "User %s is not SYSTEM or an Administrator",
1137 user_name(req, module));
1138 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1142 _PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
1144 .search = acl_search,
1146 .modify = acl_modify,
1148 .rename = acl_rename,
1149 .extended = acl_extended,
1150 .init_context = acl_module_init