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 /* TODO Is this really right? */
806 /* if (what_is_user(module) == SECURITY_SYSTEM) */
807 return ldb_next_request(module, req);
811 ac->ignore_security = true;
812 ac->dn_to_check = req->op.mod.message->dn;
813 ac->token = user_token(module);
814 ac->user_type = what_is_user(module);
815 ac->sec_result = LDB_SUCCESS;
816 if (!is_root_base_dn(ldb, req->op.mod.message->dn) && parent && !is_root_base_dn(ldb, parent)){
817 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
818 ldb_dn_get_component_name(parent,0),
819 ldb_dn_get_component_val(parent,0)->data,
820 ldb_dn_get_component_name(req->op.mod.message->dn,0),
821 ldb_dn_get_component_val(req->op.mod.message->dn,0)->data);
823 ret = make_req_access_check(module, req, ac, filter);
824 if (ret != LDB_SUCCESS){
827 return ldb_next_request(module, ac->down_req);
829 return ldb_next_request(module, req);
832 /* similar to the modify for the time being.
833 * We need to concider the special delete tree case, though - TODO */
834 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
837 struct acl_context *ac;
838 struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.del.dn);
840 struct ldb_context *ldb;
841 struct acl_private *data;
843 ldb = ldb_module_get_ctx(module);
844 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
846 if (!data->perform_check)
847 return ldb_next_request(module, req);
849 ac = talloc(req, struct acl_context);
851 return LDB_ERR_OPERATIONS_ERROR;
854 if (ac->user_type == SECURITY_SYSTEM)
855 return ldb_next_request(module, req);
859 ac->ignore_security = true;
860 ac->dn_to_check = req->op.del.dn;
861 ac->token = user_token(module);
862 ac->user_type = what_is_user(module);
863 ac->sec_result = LDB_SUCCESS;
865 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
866 ldb_dn_get_component_name(parent,0),
867 ldb_dn_get_component_val(parent,0)->data,
868 ldb_dn_get_component_name(req->op.del.dn,0),
869 ldb_dn_get_component_val(req->op.del.dn,0)->data);
870 ret = make_req_access_check(module, req, ac, filter);
872 if (ret != LDB_SUCCESS){
875 return ldb_next_request(module, ac->down_req);
878 return ldb_next_request(module, req);
881 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
883 struct ldb_dn *source_parent;
884 struct ldb_dn *dest_parent;
886 struct acl_context *ac;
888 struct ldb_context *ldb;
889 struct acl_private *data;
891 ldb = ldb_module_get_ctx(module);
892 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
894 if (!data->perform_check)
895 return ldb_next_request(module, req);
897 ac = talloc(req, struct acl_context);
899 return LDB_ERR_OPERATIONS_ERROR;
902 if (ac->user_type == SECURITY_SYSTEM)
903 return ldb_next_request(module, req);
907 ac->ignore_security = true;
908 ac->token = user_token(module);
909 ac->user_type = what_is_user(module);
910 ac->sec_result = LDB_SUCCESS;
912 /* We need to know if it is a simple rename or a move operation */
913 source_parent = ldb_dn_get_parent(req, req->op.rename.olddn);
914 dest_parent = ldb_dn_get_parent(req, req->op.rename.newdn);
916 if (ldb_dn_compare(source_parent, dest_parent) == 0){
917 /*Not a move, just rename*/
918 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
919 ldb_dn_get_component_name(dest_parent,0),
920 ldb_dn_get_component_val(dest_parent,0)->data,
921 ldb_dn_get_component_name(req->op.rename.olddn,0),
922 ldb_dn_get_component_val(req->op.rename.olddn,0)->data);
925 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
926 ldb_dn_get_component_name(dest_parent,0),
927 ldb_dn_get_component_val(dest_parent,0)->data,
928 ldb_dn_get_component_name(source_parent,0),
929 ldb_dn_get_component_val(source_parent,0)->data);
932 ret = make_req_access_check(module, req, ac, filter);
934 if (ret != LDB_SUCCESS){
937 return ldb_next_request(module, ac->down_req);
940 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
942 struct ldb_context *ldb;
943 struct acl_context *ac;
944 struct security_descriptor *sd;
945 uint32_t searchFlags;
946 uint32_t access_mask;
947 struct object_tree *ot;
950 struct ldb_message_element *element_security_descriptor;
951 struct ldb_message_element *element_object_class;
952 const struct dsdb_attribute *attr;
953 const struct dsdb_schema *schema;
954 struct GUID *oc_guid;
956 ac = talloc_get_type(req->context, struct acl_context);
957 ldb = ldb_module_get_ctx(ac->module);
958 schema = dsdb_get_schema(ldb);
960 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
962 if (ares->error != LDB_SUCCESS) {
963 return ldb_module_done(ac->req, ares->controls, ares->response, ares->error);
966 switch (ares->type) {
967 case LDB_REPLY_ENTRY:
968 switch (ac->user_type) {
969 case SECURITY_SYSTEM:
970 case SECURITY_ANONYMOUS:/*FIXME: should we let anonymous have system access*/
975 * 0. If we do not have nTSecurityDescriptor, we do not have an object in the response,
976 * so check the parent dn.
977 * 1. Call sec_access_check on empty tree
978 * 2. For each attribute call extended_access_check
979 * 3. For each attribute call build_object_tree_form_attr_list and then check with sec_access_check
982 element_security_descriptor = ldb_msg_find_element(ares->message, "nTSecurityDescriptor");
983 element_object_class = ldb_msg_find_element(ares->message, "objectClass");
984 if (!element_security_descriptor || !element_object_class)
987 sd = talloc(ldb, struct security_descriptor);
989 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
991 if(!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&element_security_descriptor->values[0],
995 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
996 DEBUG(0, ("acl_search_callback: Error parsing security descriptor\n"));
997 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
1000 oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, element_object_class->values[0].data);
1001 for (i=0; i<ares->message->num_elements; i++) {
1002 attr = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name);
1004 searchFlags = attr->searchFlags;
1009 /*status = extended_access_check(ares->message->elements[i].name, access_mask, searchFlags); */ /* Todo FIXME */
1010 ac->access_needed = SEC_ADS_READ_PROP;
1011 if (NT_STATUS_IS_OK(status)) {
1012 ot = insert_in_object_tree(req, oc_guid, NULL, ac->access_needed, NULL);
1014 insert_in_object_tree(req,
1015 &attr->schemaIDGUID,
1016 &attr->attributeSecurityGUID,
1020 status = sec_access_check_ds(sd,
1026 if (NT_STATUS_IS_OK(status)) {
1030 ldb_msg_remove_attr(ares->message, ares->message->elements[i].name);
1034 if (ac->nTSecurityDescriptor) {
1035 ldb_msg_remove_attr(ares->message, "nTSecurityDescriptor");
1036 } else if (ac->objectClass) {
1037 ldb_msg_remove_attr(ares->message, "objectClass");
1040 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1041 case LDB_REPLY_REFERRAL:
1042 return ldb_module_send_referral(ac->req, ares->referral);
1044 case LDB_REPLY_DONE:
1045 return ldb_module_done(ac->req, ares->controls,ares->response, LDB_SUCCESS);
1051 static int acl_search(struct ldb_module *module, struct ldb_request *req)
1054 struct ldb_context *ldb;
1055 struct acl_context *ac;
1057 struct ldb_control *sd_control;
1058 struct ldb_control **sd_saved_controls;
1059 struct ldb_dn * parent;
1060 struct acl_private *data;
1062 ldb = ldb_module_get_ctx(module);
1063 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1065 if (!data || !data->perform_check)
1066 return ldb_next_request(module, req);
1068 if (what_is_user(module) == SECURITY_SYSTEM)
1069 return ldb_next_request(module, req);
1071 ac = talloc_get_type(req->context, struct acl_context);
1073 ac = talloc(req, struct acl_context);
1076 return LDB_ERR_OPERATIONS_ERROR;
1078 ac->module = module;
1080 ac->ignore_security = false;
1081 ac->user_type = what_is_user(module);
1082 ac->token = user_token(module);
1083 ac->dn_to_check = req->op.search.base;
1084 ac->sec_result = LDB_SUCCESS;
1086 attrs = talloc_array(ac, const char*, 2);
1087 attrs[0] = talloc_strdup(attrs, "nTSecurityDescriptor");
1089 parent = ldb_dn_get_parent(req, ac->dn_to_check);
1090 if (!is_root_base_dn(ldb, req->op.search.base) && parent && !is_root_base_dn(ldb, parent)) {
1091 /*we have parent so check for visibility*/
1092 ret = ldb_build_search_req(&ac->down_req,
1099 ac, acl_visible_callback,
1101 if (ret != LDB_SUCCESS) {
1104 return ldb_next_request(module, ac->down_req);
1106 return acl_forward_search(ac);
1110 return ldb_next_request(module, req);
1113 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
1115 struct ldb_context *ldb = ldb_module_get_ctx(module);
1116 enum security_user_level user_type;
1117 struct acl_private *data;
1119 data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1121 if (!data->perform_check)
1122 return ldb_next_request(module, req);
1124 /* allow everybody to read the sequence number */
1125 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1126 return ldb_next_request(module, req);
1129 user_type = what_is_user(module);
1130 switch (user_type) {
1131 case SECURITY_SYSTEM:
1132 case SECURITY_ADMINISTRATOR:
1133 return ldb_next_request(module, req);
1135 ldb_asprintf_errstring(ldb,
1136 "acl_extended: attempted database modify not permitted."
1137 "User %s is not SYSTEM or an Administrator",
1138 user_name(req, module));
1139 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1143 _PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
1145 .search = acl_search,
1147 .modify = acl_modify,
1149 .rename = acl_rename,
1150 .extended = acl_extended,
1151 .init_context = acl_module_init