summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadezhda Ivanova <nadezhda.ivanova@postpath.com>2009-11-05 17:34:12 +0200
committerNadezhda Ivanova <nadezhda.ivanova@postpath.com>2009-11-05 17:34:12 +0200
commit1fc47e1228b7f32ad0d6636d09d63d3b1c124aaa (patch)
treeb08687ad14d4b97249740511935c8af9f7ea176b
parentb6303f03721d0a86e2e379bdb2e436e328c8f5cb (diff)
downloadsamba-1fc47e1228b7f32ad0d6636d09d63d3b1c124aaa.tar.gz
samba-1fc47e1228b7f32ad0d6636d09d63d3b1c124aaa.tar.bz2
samba-1fc47e1228b7f32ad0d6636d09d63d3b1c124aaa.zip
Version 1.0 of the directory service acls module.
At this point, support for checks on LDAP add, delete, rename and modify. Old kludge_acl is still there to handle the searches. This module is synchronous as the async version was impossible to debug, will be converted to async after some user testing.
-rw-r--r--source4/dsdb/samdb/ldb_modules/acl.c1305
-rw-r--r--source4/dsdb/samdb/ldb_modules/kludge_acl.c4
-rw-r--r--source4/dsdb/schema/schema_query.c14
-rw-r--r--source4/libcli/security/object_tree.c101
-rw-r--r--source4/libcli/security/security.h6
-rw-r--r--source4/scripting/python/samba/provision.py2
6 files changed, 419 insertions, 1013 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c
index 2f123145db..f96d4294c5 100644
--- a/source4/dsdb/samdb/ldb_modules/acl.c
+++ b/source4/dsdb/samdb/ldb_modules/acl.c
@@ -40,30 +40,6 @@
#include "librpc/gen_ndr/ndr_security.h"
#include "param/param.h"
-/* acl_search helper */
-struct acl_context {
-
- struct ldb_module *module;
- struct ldb_request *req;
- struct ldb_request *down_req;
-
- /*needed if we have to identify if this is SYSTEM_USER*/
- enum security_user_level user_type;
-
- uint32_t access_needed;
- struct ldb_dn * dn_to_check;
-
- /* set to true when we need to process the request as a SYSTEM_USER, regardless
- * of the user's actual rights - for example when we need to retrieve the
- * ntSecurityDescriptor */
- bool ignore_security;
- struct security_token *token;
- /*needed to identify if we have requested these attributes*/
- bool nTSecurityDescriptor;
- bool objectClass;
- int sec_result;
-};
-
struct extended_access_check_attribute {
const char *oa_name;
const uint32_t requires_rights;
@@ -73,199 +49,6 @@ struct acl_private{
bool perform_check;
};
-static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares);
-
-/*FIXME: Perhaps this should go in the .idl file*/
-#define SEC_GENERIC_ACCESS_NEVER_GRANTED ( 0xFFFFFFFF )
-
-/*Contains a part of the attributes - the ones that have predefined required rights*/
-static const struct extended_access_check_attribute extended_access_checks_table[] =
-{
- {
- .oa_name = "nTSecurityDescriptor",
- .requires_rights = SEC_FLAG_SYSTEM_SECURITY & SEC_STD_READ_CONTROL,
- },
- {
- .oa_name = "pekList",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "currentValue",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "dBCSPwd",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "unicodePwd",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "ntPwdHistory",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "priorValue",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "supplementalCredentials",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "trustAuthIncoming",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "trustAuthOutgoing",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "ImPwdHistory",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "initialAuthIncoming",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "initialAuthOutgoing",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
- {
- .oa_name = "msDS-ExecuteScriptPassword",
- .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
- },
-};
-
-static NTSTATUS extended_access_check(const char *attribute_name, const int access_rights, uint32_t searchFlags)
-{
- int i = 0;
- if (access_rights == SEC_GENERIC_ACCESS_NEVER_GRANTED) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- /*Check if the attribute is in the table first*/
- for ( i = 0; extended_access_checks_table[i].oa_name; i++ ) {
- if (ldb_attr_cmp(extended_access_checks_table[i].oa_name, attribute_name) == 0) {
- if ((access_rights & extended_access_checks_table[i].requires_rights) == access_rights) {
- return NT_STATUS_OK;
- } else {
- return NT_STATUS_ACCESS_DENIED;
- }
- }
- }
-
- /*Check for attribute whose attributeSchema has 0x80 set in searchFlags*/
- if ((searchFlags & SEARCH_FLAG_CONFIDENTIAL) == SEARCH_FLAG_CONFIDENTIAL) {
- if (((SEC_ADS_READ_PROP & SEC_ADS_CONTROL_ACCESS) & access_rights) == access_rights) {
- return NT_STATUS_OK;
- } else {
- return NT_STATUS_ACCESS_DENIED;
- }
- }
-
- /*Check attributes with *special* behaviour*/
- if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0 || ldb_attr_cmp("msDS-QuotaUsed", attribute_name) == 0){
- /*Rights required:
- *
- *(RIGHT_DS_READ_PROPERTY on the Quotas container or
- *((the client is querying the quota for the security principal it is authenticated as) and
- *(DS-Query-Self-Quota control access right on the Quotas container))
- */
- }
-
- if (ldb_attr_cmp("userPassword", attribute_name) == 0) {
- /*When the dSHeuristics.fUserPwdSupport flag is false, the requester must be granted RIGHT_DS_READ_PROPERTY.
- *When the dSHeuristics.fUserPwdSupport flag is true, access is never granted.
- */
- }
-
- if (ldb_attr_cmp("sDRightsEffective", attribute_name) == 0) {
- /*FIXME:3.1.1.4.5.4 in MS-ADTS*/
- }
-
- if (ldb_attr_cmp("allowedChildClassesEffective", attribute_name) == 0) {
- /*FIXME:3.1.1.4.5.5 in MS-ADTS*/
- }
-
- if (ldb_attr_cmp("allowedAttributesEffective", attribute_name) == 0) {
- /*FIXME:3.1.1.4.5.7 in MS-ADTS*/
- }
-
- if (ldb_attr_cmp("msDS-Approx-Immed-Subordinates", attribute_name) == 0) {
- /*FIXME:3.1.1.4.5.15 in MS-ADTS*/
- }
-
- if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0) {
- /*FIXME:3.1.1.4.5.22 in MS-ADTS*/
- }
-
- if (ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0 || ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0) {
- /*The security context of the requester must be granted the following rights on the replPropertyMetaData attribute:
- *(RIGHT_DS_READ_PROPERTY)or (DS-Replication-Manage-Topology by ON!nTSecurityDescriptor)
- */
- }
-
- if (ldb_attr_cmp("msDS-NCReplInboundNeighbors", attribute_name) == 0) {
- /*The security context of the requester must be granted the following rights on repsFrom:
- *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
- */
- }
-
- if (ldb_attr_cmp("msDS-NCReplOutboundNeighbors", attribute_name) == 0) {
- /*The security context of the requester must be granted the following rights on repsTo:
- *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
- */
- }
-
- if (ldb_attr_cmp("msDS-NCReplCursors", attribute_name) == 0) {
- /*The security context of the requester must be granted the following rights on replUpToDateVector: (RIGHT_DS_READ_PROPERTY)
- *or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
- */
- }
-
- if (ldb_attr_cmp("msDS-IsUserCachableAtRodc", attribute_name) == 0) {
- /*The security context of the requester must be granted
- *the DS-Replication-Secrets-Synchronize control access right on the root of the default NC.
- */
- }
-
- return NT_STATUS_OK;
-}
-
-/* Builds an object tree for object specific access checks */
-static struct object_tree * build_object_tree_form_attr_list(TALLOC_CTX *mem_ctx, /* Todo this context or separate? */
- struct ldb_context *ldb,
- const char ** attr_names,
- int num_attrs,
- const char * object_class,
- uint32_t init_access)
-{
- const struct dsdb_schema *schema = dsdb_get_schema(ldb);
- const struct GUID *oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, object_class);
- struct object_tree *tree;
- int i;
-
- if (!oc_guid)
- return NULL;
-
- tree = insert_in_object_tree(mem_ctx, oc_guid, NULL, init_access, NULL);
- if (attr_names){
- for (i=0; i < num_attrs; i++){
- const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema,attr_names[i]);
- if (attribute)
- insert_in_object_tree(mem_ctx,
- &attribute->schemaIDGUID,
- &attribute->attributeSecurityGUID,
- init_access,
- tree);
- }
- }
- return tree;
-}
-
bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check)
{
int result;
@@ -274,559 +57,306 @@ bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check)
return (result==0);
}
-static int acl_op_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- struct acl_context *ac;
-
- ac = talloc_get_type(req->context, struct acl_context);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- if (ares->type != LDB_REPLY_DONE) {
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
-}
-
-
-static int acl_access_check_add(struct ldb_reply *ares,
- struct acl_context *ac,
- struct security_descriptor *sd)
+static enum security_user_level what_is_user(struct ldb_module *module)
{
- uint32_t access_granted = 0;
- NTSTATUS status;
- struct ldb_dn *parent;
- struct ldb_dn *grandparent;
- struct object_tree *tree = NULL;
-
- parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
- grandparent = ldb_dn_get_parent(ac->req, parent);
- if (ldb_dn_compare(ares->message->dn, grandparent) == 0)
- status = sec_access_check_ds(sd, ac->token,
- SEC_ADS_LIST,
- &access_granted,
- NULL);
- else if (ldb_dn_compare(ares->message->dn, parent) == 0){
- struct ldb_message_element *oc_el;
- struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
- const struct dsdb_schema *schema = dsdb_get_schema(ldb);
- int i;
-
- oc_el = ldb_msg_find_element(ares->message, "objectClass");
- if (!oc_el || oc_el->num_values == 0)
- return LDB_SUCCESS;
- for (i = 0; i < oc_el->num_values; i++){
- const struct GUID *guid = class_schemaid_guid_by_lDAPDisplayName(schema,
- oc_el->values[i].data);
- ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
- tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_CREATE_CHILD,
- tree);
- status = sec_access_check_ds(sd, ac->token, SEC_ADS_CREATE_CHILD,&access_granted, tree);
- if (NT_STATUS_IS_OK(status))
- ac->sec_result = LDB_SUCCESS;
- }
- }
- else
- return LDB_SUCCESS;
-
- return ac->sec_result;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct auth_session_info *session_info
+ = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
+ return security_session_user_level(session_info);
}
-static int acl_access_check_modify(struct ldb_reply *ares, struct acl_context *ac,
- struct security_descriptor *sd)
+static struct security_token *acl_user_token(struct ldb_module *module)
{
- uint32_t access_granted = 0;
- NTSTATUS status;
- struct ldb_dn *parent;
- struct object_tree *tree = NULL;
-
- parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
- if (ldb_dn_compare(ares->message->dn, parent) == 0)
- status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
- else if (ldb_dn_compare(ares->message->dn, ac->req->op.add.message->dn) == 0){
- struct ldb_message_element *oc_el;
- struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
- const struct dsdb_schema *schema = dsdb_get_schema(ldb);
- int i;
- struct GUID *guid;
- oc_el = ldb_msg_find_element(ares->message, "objectClass");
- if (!oc_el || oc_el->num_values == 0)
- return LDB_SUCCESS;
-
- guid = class_schemaid_guid_by_lDAPDisplayName(schema,
- oc_el->values[oc_el->num_values-1].data);
- tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_WRITE_PROP,
- tree);
- for (i=0; i < ac->req->op.mod.message->num_elements; i++){
- const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
- ac->req->op.mod.message->elements[i].name);
- if (!attr)
- return LDB_ERR_OPERATIONS_ERROR; /* What should we actually return here? */
- insert_in_object_tree(ac, &attr->schemaIDGUID,
- &attr->attributeSecurityGUID, ac->access_needed, tree);
- }
- status = sec_access_check_ds(sd, ac->token, SEC_ADS_WRITE_PROP ,&access_granted, tree);
- if (!NT_STATUS_IS_OK(status))
- ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct auth_session_info *session_info
+ = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
+ if(!session_info) {
+ return NULL;
}
- else
- return LDB_SUCCESS;
- return ac->sec_result;
-}
-/*TODO*/
-static int acl_access_check_rename(struct ldb_reply *ares, struct acl_context *ac,
- struct security_descriptor *sd)
-{
- return ac->sec_result;
+ return session_info->security_token;
}
-static int acl_access_check_delete(struct ldb_reply *ares, struct acl_context *ac,
- struct security_descriptor *sd)
+static int acl_module_init(struct ldb_module *module)
{
- uint32_t access_granted = 0;
- NTSTATUS status;
- struct ldb_dn *parent;
- struct object_tree *tree = NULL;
-
- parent = ldb_dn_get_parent(ac->req, ac->req->op.del.dn);
- if (ldb_dn_compare(ares->message->dn, parent) == 0){
- status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
- if (!NT_STATUS_IS_OK(status)){
- ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
- return ac->sec_result;
- }
- status = sec_access_check_ds(sd, ac->token, SEC_ADS_DELETE_CHILD,&access_granted, NULL);
- if (NT_STATUS_IS_OK(status)){
- ac->sec_result = LDB_SUCCESS;
- return ac->sec_result;
- }
- }
- else if (ldb_dn_compare(ares->message->dn, ac->req->op.del.dn) == 0){
- status = sec_access_check_ds(sd, ac->token, SEC_STD_DELETE, &access_granted, NULL);
- if (!NT_STATUS_IS_OK(status))
- ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
- }
- return ac->sec_result;
-}
+ struct ldb_context *ldb;
+ struct acl_private *data;
+ int ret;
-static int acl_access_check_search(struct ldb_reply *ares, struct acl_context *ac,
- struct security_descriptor *sd)
-{
- uint32_t access_granted;
- NTSTATUS status;
- struct ldb_dn *parent;
+ ldb = ldb_module_get_ctx(module);
- if (ac->user_type == SECURITY_SYSTEM || ac->user_type == SECURITY_ANONYMOUS) {
- return LDB_SUCCESS;/*FIXME: we have anonymous access*/
+ ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "acl_module_init: Unable to register control with rootdse!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
}
- parent = ldb_dn_get_parent(ac->req, ac->dn_to_check);
- ac->sec_result = LDB_SUCCESS;
- if (ldb_dn_compare(ares->message->dn, parent) == 0) {
- status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
- if (!NT_STATUS_IS_OK(status)) {
- ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
- }
- }
+ data = talloc(module, struct acl_private);
+ data->perform_check = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
+ NULL, "acl", "perform", false);
+ ldb_module_set_private(module, data);
- return ac->sec_result;
+ return ldb_next_init(module);
}
-static int acl_perform_access_check(struct ldb_request *req, struct ldb_reply *ares,
- struct acl_context *ac)
+static int get_sd_from_result(TALLOC_CTX *mem_ctx,
+ struct ldb_result *acl_res,
+ struct security_descriptor **sd)
{
- struct ldb_message_element *oc_el;
- struct security_descriptor *sd;
+ struct ldb_message_element *sd_element;
enum ndr_err_code ndr_err;
- oc_el = ldb_msg_find_element(ares->message, "ntSecurityDescriptor");
- if (!oc_el || oc_el->num_values == 0)
+ sd_element = ldb_msg_find_element(acl_res->msgs[0], "ntSecurityDescriptor");
+ if (!sd_element) {
return LDB_SUCCESS;
-
- sd = talloc(ac, struct security_descriptor);
- if(!sd) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_ERR_OPERATIONS_ERROR);
}
- ndr_err = ndr_pull_struct_blob(&oc_el->values[0], sd, NULL, sd,
+ *sd = talloc(mem_ctx, struct security_descriptor);
+ if(!*sd) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, NULL, *sd,
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err))
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_ERR_OPERATIONS_ERROR);
- switch (ac->req->operation) {
- case LDB_SEARCH:
- return acl_access_check_search(ares, ac, sd);
- case LDB_ADD:
- return acl_access_check_add(ares, ac, sd);
- case LDB_MODIFY:
- return acl_access_check_modify(ares, ac, sd);
- case LDB_DELETE:
- return acl_access_check_delete(ares, ac, sd);
- case LDB_RENAME:
- return acl_access_check_rename(ares, ac, sd);
- default:
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_ERR_OPERATIONS_ERROR);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
+
return LDB_SUCCESS;
}
-static int acl_forward_add(struct ldb_reply *ares,
- struct acl_context *ac)
+static const struct GUID *get_oc_guid_from_result(struct ldb_module *module,
+ struct ldb_result *acl_res)
{
- struct ldb_request *newreq;
- struct ldb_context *ldb;
- int ret;
-
- ldb = ldb_module_get_ctx(ac->module);
- ret = ldb_build_add_req(&newreq,ldb,
- ac,
- ac->req->op.add.message,
- ac->req->controls,
- ac,
- acl_op_callback,
- ac->req);
- if (ret != LDB_SUCCESS)
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_ERR_OPERATIONS_ERROR);
- return ldb_next_request(ac->module, newreq);
-}
+ struct ldb_message_element *oc_el;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
-static int acl_forward_modify(struct ldb_reply *ares,
- struct acl_context *ac)
-{
- struct ldb_request *newreq;
- struct ldb_context *ldb;
- int ret;
+ oc_el = ldb_msg_find_element(acl_res->msgs[0], "objectClass");
+ if (!oc_el) {
+ return NULL;
+ }
- ldb = ldb_module_get_ctx(ac->module);
- ret = ldb_build_mod_req(&newreq,ldb,
- ac,
- ac->req->op.mod.message,
- ac->req->controls,
- ac,
- acl_op_callback,
- ac->req);
- if (ret != LDB_SUCCESS)
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_ERR_OPERATIONS_ERROR);
- return ldb_next_request(ac->module, newreq);
+ return class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb),
+ (char *)oc_el->values[oc_el->num_values-1].data);
}
-static int acl_forward_delete(struct ldb_reply *ares,
- struct acl_context *ac)
+static void acl_debug(struct security_descriptor *sd,
+ struct security_token *token,
+ struct ldb_dn *dn,
+ bool denied,
+ int level)
{
- struct ldb_request *newreq;
- struct ldb_context *ldb;
- int ret;
-
- ldb = ldb_module_get_ctx(ac->module);
- ret = ldb_build_del_req(&newreq, ldb,
- ac,
- ac->req->op.del.dn,
- ac->req->controls,
- ac,
- acl_op_callback,
- ac->req);
- if (ret != LDB_SUCCESS)
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_ERR_OPERATIONS_ERROR);
- return ldb_next_request(ac->module, newreq);
-}
+ if (denied) {
+ DEBUG(level, ("Access on %s denied", ldb_dn_get_linearized(dn)));
+ } else {
+ DEBUG(level, ("Access on %s granted", ldb_dn_get_linearized(dn)));
+ }
-static int acl_forward_rename(struct ldb_reply *ares,
- struct acl_context *ac)
-{
- return LDB_SUCCESS;
+ DEBUG(level,("Security context: %s\n",
+ ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_token,"", token)));
+ DEBUG(level,("Security descriptor: %s\n",
+ ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor,"", sd)));
}
-static int acl_forward_search(struct acl_context *ac)
+static int check_access_on_dn(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ uint32_t access,
+ struct object_tree *tree)
{
int ret;
- const char * const *attrs;
- struct ldb_control *sd_control;
- struct ldb_control **sd_saved_controls;
- struct ldb_context *ldb;
- struct ldb_request *newreq;
-
- ldb = ldb_module_get_ctx(ac->module);
- attrs = ac->req->op.search.attrs;
- if (attrs) {
- ac->nTSecurityDescriptor = false;
- ac->objectClass = false;
- if (!ldb_attr_in_list(ac->req->op.search.attrs, "nTSecurityDescriptor")) {
- attrs = ldb_attr_list_copy_add(ac, attrs, "nTSecurityDescriptor");
- ac->nTSecurityDescriptor = true;
- }
- if (!ldb_attr_in_list(ac->req->op.search.attrs, "objectClass")) {
- attrs = ldb_attr_list_copy_add(ac, attrs, "objectClass");
- ac->objectClass = true;
- }
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_result *acl_res;
+ struct security_descriptor *sd = NULL;
+ NTSTATUS status;
+ uint32_t access_granted;
+ static const char *acl_attrs[] = {
+ "nTSecurityDescriptor",
+ NULL
+ };
+
+ ret = ldb_search(ldb, mem_ctx, &acl_res, dn, LDB_SCOPE_BASE, acl_attrs, NULL);
+ /* we sould be able to find the parent */
+ if (ret != LDB_SUCCESS) {
+ DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(dn)));
+ return ret;
}
- ret = ldb_build_search_req_ex(&newreq,ldb,
- ac,
- ac->req->op.search.base,
- ac->req->op.search.scope,
- ac->req->op.search.tree,
- attrs,
- ac->req->controls,
- ac, acl_search_callback,
- ac->req);
+
+ ret = get_sd_from_result(mem_ctx, acl_res, &sd);
if (ret != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
+ return LDB_ERR_OPERATIONS_ERROR;
}
- /* check if there's an SD_FLAGS control */
- sd_control = ldb_request_get_control(newreq, LDB_CONTROL_SD_FLAGS_OID);
- if (sd_control) {
- /* save it locally and remove it from the list */
- /* we do not need to replace them later as we
- * are keeping the original req intact */
- if (!save_controls(sd_control, newreq, &sd_saved_controls)) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ /* Theoretically we pass the check if the object has no sd */
+ if (!sd) {
+ return LDB_SUCCESS;
}
- return ldb_next_request(ac->module, newreq);
-}
-
-static int acl_forward_request(struct ldb_reply *ares,
- struct acl_context *ac)
-{
- switch (ac->req->operation) {
- case LDB_SEARCH:
- return acl_forward_search(ac);
- case LDB_ADD:
- return acl_forward_add(ares,ac);
- case LDB_MODIFY:
- return acl_forward_modify(ares,ac);
- case LDB_DELETE:
- return acl_forward_delete(ares,ac);
- case LDB_RENAME:
- return acl_forward_rename(ares,ac);
- default:
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_ERR_OPERATIONS_ERROR);
+ status = sec_access_check_ds(sd, acl_user_token(module),
+ access,
+ &access_granted,
+ tree);
+ if (!NT_STATUS_IS_OK(status)) {
+ acl_debug(sd,
+ acl_user_token(module),
+ dn,
+ true,
+ 10);
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
return LDB_SUCCESS;
}
-static int acl_visible_callback(struct ldb_request *req, struct ldb_reply *ares)
+static int acl_add(struct ldb_module *module, struct ldb_request *req)
{
- struct acl_context *ac;
-
- ac = talloc_get_type(req->context, struct acl_context);
+ int ret;
+ struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.add.message->dn);
+ struct ldb_context *ldb;
+ struct ldb_message_element *oc_el;
+ const struct GUID *guid;
+ struct object_tree *root = NULL;
+ struct object_tree *new_node = NULL;
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
+ if (what_is_user(module) == SECURITY_SYSTEM) {
+ return ldb_next_request(module, req);
}
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return ldb_next_request(module, req);
}
-
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
- return acl_perform_access_check(req, ares, ac);
- case LDB_REPLY_REFERRAL:
- return ldb_module_send_referral(ac->req, ares->referral); /* what to do here actually? */
- case LDB_REPLY_DONE:
- if (ac->sec_result != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ac->sec_result);
- }
- return acl_forward_request(ares,ac);
- default:
- break;
+ ldb = ldb_module_get_ctx(module);
+ /* Creating an NC. There is probably something we should do here,
+ * but we will establish that later */
+ if ((ldb_dn_compare(req->op.add.message->dn, (ldb_get_schema_basedn(ldb))) == 0) ||
+ (ldb_dn_compare(req->op.add.message->dn, (ldb_get_config_basedn(ldb))) == 0) ||
+ (ldb_dn_compare(req->op.add.message->dn, (ldb_get_root_basedn(ldb))) == 0)) {
+ return ldb_next_request(module, req);
}
- return LDB_SUCCESS;
-}
-
-static enum security_user_level what_is_user(struct ldb_module *module)
-{
- struct ldb_context *ldb = ldb_module_get_ctx(module);
- struct auth_session_info *session_info
- = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
- return security_session_user_level(session_info);
-}
-static struct security_token * user_token(struct ldb_module *module)
-{
- struct ldb_context *ldb = ldb_module_get_ctx(module);
- struct auth_session_info *session_info
- = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
- if(!session_info) {
- return NULL;
+ oc_el = ldb_msg_find_element(req->op.add.message, "objectClass");
+ if (!oc_el || oc_el->num_values == 0) {
+ DEBUG(10,("acl:operation error %s\n", ldb_dn_get_linearized(req->op.add.message->dn)));
+ return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
}
- return session_info->security_token;
-}
-
-static int make_req_access_check(struct ldb_module *module, struct ldb_request *req,
- struct acl_context *ac, const char *filter)
-{
- struct ldb_context *ldb;
- int ret;
- const char **attrs = talloc_array(ac, const char *, 3);
- struct ldb_parse_tree *tree = ldb_parse_tree(req, filter);
+ guid = class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb),
+ (char *)oc_el->values[oc_el->num_values-1].data);
- attrs[0] = talloc_strdup(attrs, "ntSecurityDescriptor");
- attrs[1] = talloc_strdup(attrs, "objectClass");
- attrs[2] = NULL;
-
- ldb = ldb_module_get_ctx(module);
- ret = ldb_build_search_req_ex(&ac->down_req,
- ldb, ac,
- ac->dn_to_check,
- LDB_SCOPE_SUBTREE,
- tree,
- attrs,
- NULL,
- ac, acl_visible_callback,
- req);
- return ret;
-}
-
-static const char *user_name(TALLOC_CTX *mem_ctx, struct ldb_module *module)
-{
- struct ldb_context *ldb = ldb_module_get_ctx(module);
- struct auth_session_info *session_info
- = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
- if (!session_info) {
- return "UNKNOWN (NULL)";
+ if (!insert_in_object_tree(req, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return talloc_asprintf(mem_ctx, "%s\\%s",
- session_info->server_info->domain_name,
- session_info->server_info->account_name);
-}
-
-static int acl_module_init(struct ldb_module *module)
-{
- struct ldb_context *ldb;
- struct acl_private *data;
- int ret;
-
- ldb = ldb_module_get_ctx(module);
-
- ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
+ ret = check_access_on_dn(module, req, parent, SEC_ADS_CREATE_CHILD, root);
if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "acl_module_init: Unable to register control with rootdse!\n");
- return LDB_ERR_OPERATIONS_ERROR;
+ return ret;
}
- data = talloc(module, struct acl_private);
- data->perform_check = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
- NULL, "acl", "perform", false);
- ldb_module_set_private(module, data);
-
- return ldb_next_init(module);
+ return ldb_next_request(module, req);
}
-static int acl_add(struct ldb_module *module, struct ldb_request *req)
+static int acl_modify(struct ldb_module *module, struct ldb_request *req)
{
int ret;
- struct acl_context *ac;
- struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.add.message->dn);
- char * filter;
- struct ldb_context *ldb;
- struct acl_private *data;
-
- ldb = ldb_module_get_ctx(module);
- data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
-
- if (!data->perform_check)
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+ int i;
+ const struct GUID *guid;
+ uint32_t access_granted;
+ struct object_tree *root = NULL;
+ struct object_tree *new_node = NULL;
+ NTSTATUS status;
+ struct ldb_result *acl_res;
+ struct security_descriptor *sd;
+ TALLOC_CTX *tmp_ctx = talloc_new(req);
+ static const char *acl_attrs[] = {
+ "nTSecurityDescriptor",
+ "objectClass",
+ NULL
+ };
+
+ DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name));
+ if (what_is_user(module) == SECURITY_SYSTEM) {
return ldb_next_request(module, req);
-
- ac = talloc(req, struct acl_context);
- if (ac == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
}
-
- if (what_is_user(module) == SECURITY_SYSTEM)
+ if (ldb_dn_is_special(req->op.mod.message->dn)) {
return ldb_next_request(module, req);
-
- ac->module = module;
- ac->req = req;
- ac->ignore_security = true;
- ac->dn_to_check = ldb_dn_get_parent(req, parent);
- ac->token = user_token(module);
- ac->user_type = what_is_user(module);
- ac->sec_result = LDB_SUCCESS;
- if (!is_root_base_dn(ldb, req->op.add.message->dn) && parent && !is_root_base_dn(ldb, parent)){
- filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
- ldb_dn_get_component_name(parent,0),
- ldb_dn_get_component_val(parent,0)->data,
- ldb_dn_get_component_name(ac->dn_to_check,0),
- ldb_dn_get_component_val(ac->dn_to_check,0)->data);
-
- ret = make_req_access_check(module, req, ac, filter);
- if (ret != LDB_SUCCESS){
- return ret;
- }
- return ldb_next_request(module, ac->down_req);
}
- return ldb_next_request(module, req);
-}
+ ret = ldb_search(ldb, req, &acl_res, req->op.mod.message->dn,
+ LDB_SCOPE_BASE, acl_attrs, NULL);
-static int acl_modify(struct ldb_module *module, struct ldb_request *req)
-{
- int ret;
- struct acl_context *ac;
- struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.mod.message->dn);
- char * filter;
- struct ldb_context *ldb;
- struct acl_private *data;
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- ldb = ldb_module_get_ctx(module);
- data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
+ ret = get_sd_from_result(req, acl_res, &sd);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(10, ("acl_modify: cannot get descriptor\n"));
+ return ret;
+ }
+ /* Theoretically we pass the check if the object has no sd */
+ if (!sd) {
+ return LDB_SUCCESS;
+ }
- if (!data->perform_check)
- return ldb_next_request(module, req);
+ guid = get_oc_guid_from_result(module,acl_res);
+ if (!guid) {
+ DEBUG(10, ("acl_modify: cannot get guid\n"));
+ goto fail;
+ }
- ac = talloc(req, struct acl_context);
- if (ac == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
+ if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
+ &root, &new_node)) {
+ DEBUG(10, ("acl_modify: cannot add to object tree\n"));
+ goto fail;
}
+ for (i=0; i < req->op.mod.message->num_elements; i++){
+ const struct dsdb_attribute *attr;
+ /* clearTextPassword is not in schema */
+ if (strcmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) {
+ attr = dsdb_attribute_by_lDAPDisplayName(schema, "unicodePwd");
+ } else {
+ attr = dsdb_attribute_by_lDAPDisplayName(schema,
+ req->op.mod.message->elements[i].name);
+ }
-/* TODO Is this really right? */
-/* if (what_is_user(module) == SECURITY_SYSTEM) */
- return ldb_next_request(module, req);
+ if (!attr) {
+ DEBUG(10, ("acl_modify: cannot find attribute %s\n",
+ req->op.mod.message->elements[i].name));
+ goto fail;
+ }
+ if (!insert_in_object_tree(tmp_ctx,
+ &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
+ &new_node, &new_node)) {
+ DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n"));
+ goto fail;
+ }
- ac->module = module;
- ac->req = req;
- ac->ignore_security = true;
- ac->dn_to_check = req->op.mod.message->dn;
- ac->token = user_token(module);
- ac->user_type = what_is_user(module);
- ac->sec_result = LDB_SUCCESS;
- if (!is_root_base_dn(ldb, req->op.mod.message->dn) && parent && !is_root_base_dn(ldb, parent)){
- filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
- ldb_dn_get_component_name(parent,0),
- ldb_dn_get_component_val(parent,0)->data,
- ldb_dn_get_component_name(req->op.mod.message->dn,0),
- ldb_dn_get_component_val(req->op.mod.message->dn,0)->data);
-
- ret = make_req_access_check(module, req, ac, filter);
- if (ret != LDB_SUCCESS){
- return ret;
+ if (!insert_in_object_tree(tmp_ctx,
+ &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) {
+ DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n"));
+ goto fail;
}
- return ldb_next_request(module, ac->down_req);
}
+
+ status = sec_access_check_ds(sd, acl_user_token(module),
+ SEC_ADS_WRITE_PROP,
+ &access_granted,
+ root);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Object %s nas no write property access\n",
+ ldb_dn_get_linearized(req->op.mod.message->dn)));
+ acl_debug(sd,
+ acl_user_token(module),
+ req->op.mod.message->dn,
+ true,
+ 10);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ talloc_free(tmp_ctx);
return ldb_next_request(module, req);
+fail:
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
}
/* similar to the modify for the time being.
@@ -834,319 +364,172 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
static int acl_delete(struct ldb_module *module, struct ldb_request *req)
{
int ret;
- struct acl_context *ac;
- struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.del.dn);
- char * filter;
+ struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn);
struct ldb_context *ldb;
- struct acl_private *data;
-
- ldb = ldb_module_get_ctx(module);
- data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
- if (!data->perform_check)
+ DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
+ if (what_is_user(module) == SECURITY_SYSTEM) {
return ldb_next_request(module, req);
-
- ac = talloc(req, struct acl_context);
- if (ac == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
}
- if (ac->user_type == SECURITY_SYSTEM)
+ if (ldb_dn_is_special(req->op.del.dn)) {
return ldb_next_request(module, req);
-
- ac->module = module;
- ac->req = req;
- ac->ignore_security = true;
- ac->dn_to_check = req->op.del.dn;
- ac->token = user_token(module);
- ac->user_type = what_is_user(module);
- ac->sec_result = LDB_SUCCESS;
- if (parent) {
- filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
- ldb_dn_get_component_name(parent,0),
- ldb_dn_get_component_val(parent,0)->data,
- ldb_dn_get_component_name(req->op.del.dn,0),
- ldb_dn_get_component_val(req->op.del.dn,0)->data);
- ret = make_req_access_check(module, req, ac, filter);
-
- if (ret != LDB_SUCCESS){
- return ret;
- }
- return ldb_next_request(module, ac->down_req);
}
-
- return ldb_next_request(module, req);
-}
-
-static int acl_rename(struct ldb_module *module, struct ldb_request *req)
-{
- struct ldb_dn *source_parent;
- struct ldb_dn *dest_parent;
- int ret;
- struct acl_context *ac;
- char * filter;
- struct ldb_context *ldb;
- struct acl_private *data;
-
ldb = ldb_module_get_ctx(module);
- data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
-
- if (!data->perform_check)
+ /* first check if we have delete object right */
+ ret = check_access_on_dn(module, req, req->op.del.dn, SEC_STD_DELETE, NULL);
+ if (ret == LDB_SUCCESS) {
return ldb_next_request(module, req);
-
- ac = talloc(req, struct acl_context);
- if (ac == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
}
- if (ac->user_type == SECURITY_SYSTEM)
- return ldb_next_request(module, req);
-
- ac->module = module;
- ac->req = req;
- ac->ignore_security = true;
- ac->token = user_token(module);
- ac->user_type = what_is_user(module);
- ac->sec_result = LDB_SUCCESS;
-
- /* We need to know if it is a simple rename or a move operation */
- source_parent = ldb_dn_get_parent(req, req->op.rename.olddn);
- dest_parent = ldb_dn_get_parent(req, req->op.rename.newdn);
-
- if (ldb_dn_compare(source_parent, dest_parent) == 0){
- /*Not a move, just rename*/
- filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
- ldb_dn_get_component_name(dest_parent,0),
- ldb_dn_get_component_val(dest_parent,0)->data,
- ldb_dn_get_component_name(req->op.rename.olddn,0),
- ldb_dn_get_component_val(req->op.rename.olddn,0)->data);
+ /* Nope, we don't have delete object. Lets check if we have delete child on the parent */
+ /* No parent, so check fails */
+ if ((ldb_dn_compare(req->op.del.dn, (ldb_get_schema_basedn(ldb))) == 0) ||
+ (ldb_dn_compare(req->op.del.dn, (ldb_get_config_basedn(ldb))) == 0) ||
+ (ldb_dn_compare(req->op.del.dn, (ldb_get_root_basedn(ldb))) == 0)) {
+ DEBUG(10,("acl:deleting an NC\n"));
+ return ldb_module_done(req, NULL, NULL, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS);
}
- else{
- filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))",
- ldb_dn_get_component_name(dest_parent,0),
- ldb_dn_get_component_val(dest_parent,0)->data,
- ldb_dn_get_component_name(source_parent,0),
- ldb_dn_get_component_val(source_parent,0)->data);
- }
-
- ret = make_req_access_check(module, req, ac, filter);
- if (ret != LDB_SUCCESS){
+ ret = check_access_on_dn(module, req, parent, SEC_ADS_DELETE_CHILD, NULL);
+ if (ret != LDB_SUCCESS) {
return ret;
- }
- return ldb_next_request(module, ac->down_req);
+ }
+ return ldb_next_request(module, req);
}
-static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+static int acl_rename(struct ldb_module *module, struct ldb_request *req)
{
+ int ret;
+ struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn);
+ struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn);
struct ldb_context *ldb;
- struct acl_context *ac;
- struct security_descriptor *sd;
- uint32_t searchFlags;
- uint32_t access_mask;
- struct object_tree *ot;
- int i, ret;
+ struct security_descriptor *sd = NULL;
+ struct ldb_result *acl_res;
+ const struct GUID *guid;
+ struct object_tree *root = NULL;
+ struct object_tree *new_node = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(req);
NTSTATUS status;
- struct ldb_message_element *element_security_descriptor;
- struct ldb_message_element *element_object_class;
- const struct dsdb_attribute *attr;
- const struct dsdb_schema *schema;
- struct GUID *oc_guid;
-
- ac = talloc_get_type(req->context, struct acl_context);
- ldb = ldb_module_get_ctx(ac->module);
- schema = dsdb_get_schema(ldb);
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+ uint32_t access_granted;
+ static const char *acl_attrs[] = {
+ "nTSecurityDescriptor",
+ "objectClass",
+ NULL
+ };
+
+ DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
+ if (what_is_user(module) == SECURITY_SYSTEM) {
+ return ldb_next_request(module, req);
}
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls, ares->response, ares->error);
+ if (ldb_dn_is_special(req->op.rename.olddn)) {
+ return ldb_next_request(module, req);
}
+ ldb = ldb_module_get_ctx(module);
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
- switch (ac->user_type) {
- case SECURITY_SYSTEM:
- case SECURITY_ANONYMOUS:/*FIXME: should we let anonymous have system access*/
- break;
- default:
- /* Access checks
- *
- * 0. If we do not have nTSecurityDescriptor, we do not have an object in the response,
- * so check the parent dn.
- * 1. Call sec_access_check on empty tree
- * 2. For each attribute call extended_access_check
- * 3. For each attribute call build_object_tree_form_attr_list and then check with sec_access_check
- *
- */
- element_security_descriptor = ldb_msg_find_element(ares->message, "nTSecurityDescriptor");
- element_object_class = ldb_msg_find_element(ares->message, "objectClass");
- if (!element_security_descriptor || !element_object_class)
- break;
-
- sd = talloc(ldb, struct security_descriptor);
- if(!sd) {
- return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
- }
- if(!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&element_security_descriptor->values[0],
- ldb,
- NULL,
- sd,
- (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
- DEBUG(0, ("acl_search_callback: Error parsing security descriptor\n"));
- return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
- }
-
- oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, element_object_class->values[0].data);
- for (i=0; i<ares->message->num_elements; i++) {
- attr = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name);
- if (attr) {
- searchFlags = attr->searchFlags;
- } else {
- searchFlags = 0x0;
- }
-
- /*status = extended_access_check(ares->message->elements[i].name, access_mask, searchFlags); */ /* Todo FIXME */
- ac->access_needed = SEC_ADS_READ_PROP;
- if (NT_STATUS_IS_OK(status)) {
- ot = insert_in_object_tree(req, oc_guid, NULL, ac->access_needed, NULL);
-
- insert_in_object_tree(req,
- &attr->schemaIDGUID,
- &attr->attributeSecurityGUID,
- ac->access_needed,
- ot);
-
- status = sec_access_check_ds(sd,
- ac->token,
- ac->access_needed,
- &access_mask,
- ot);
-
- if (NT_STATUS_IS_OK(status)) {
- continue;
- }
- }
- ldb_msg_remove_attr(ares->message, ares->message->elements[i].name);
- }
- break;
- }
- if (ac->nTSecurityDescriptor) {
- ldb_msg_remove_attr(ares->message, "nTSecurityDescriptor");
- } else if (ac->objectClass) {
- ldb_msg_remove_attr(ares->message, "objectClass");
- }
-
- return ldb_module_send_entry(ac->req, ares->message, ares->controls);
- case LDB_REPLY_REFERRAL:
- return ldb_module_send_referral(ac->req, ares->referral);
-
- case LDB_REPLY_DONE:
- return ldb_module_done(ac->req, ares->controls,ares->response, LDB_SUCCESS);
+ /* search to include deleted objects */
+ ret = ldb_search(ldb, req, &acl_res, req->op.rename.olddn,
+ LDB_SCOPE_BASE, acl_attrs, NULL);
+ /* we sould be able to find the parent */
+ if (ret != LDB_SUCCESS) {
+ DEBUG(10,("acl: failed to find object %s\n",
+ ldb_dn_get_linearized(req->op.rename.olddn)));
+ return ret;
}
- return LDB_SUCCESS;
-}
+ guid = get_oc_guid_from_result(module,acl_res);
+ if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
+ &root, &new_node)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ };
-static int acl_search(struct ldb_module *module, struct ldb_request *req)
-{
- int ret;
- struct ldb_context *ldb;
- struct acl_context *ac;
- const char **attrs;
- struct ldb_control *sd_control;
- struct ldb_control **sd_saved_controls;
- struct ldb_dn * parent;
- struct acl_private *data;
+ guid = attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb),
+ "name");
+ if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
+ &new_node, &new_node)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ };
- ldb = ldb_module_get_ctx(module);
- data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
+ ret = get_sd_from_result(req, acl_res, &sd);
- if (!data || !data->perform_check)
- return ldb_next_request(module, req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* Theoretically we pass the check if the object has no sd */
+ if (!sd) {
+ return LDB_SUCCESS;
+ }
+ status = sec_access_check_ds(sd, acl_user_token(module),
+ SEC_ADS_WRITE_PROP,
+ &access_granted,
+ root);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Object %s nas no wp on name\n",
+ ldb_dn_get_linearized(req->op.rename.olddn)));
+ acl_debug(sd,
+ acl_user_token(module),
+ req->op.rename.olddn,
+ true,
+ 10);
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
- if (what_is_user(module) == SECURITY_SYSTEM)
+ if (ldb_dn_compare(oldparent, newparent) == 0) {
+ /* regular rename, not move, nothing more to do */
return ldb_next_request(module, req);
+ }
- ac = talloc_get_type(req->context, struct acl_context);
- if ( ac == NULL ) {
- ac = talloc(req, struct acl_context);
- if (ac == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ac->module = module;
- ac->req = req;
- ac->ignore_security = false;
- ac->user_type = what_is_user(module);
- ac->token = user_token(module);
- ac->dn_to_check = req->op.search.base;
- ac->sec_result = LDB_SUCCESS;
-
- attrs = talloc_array(ac, const char*, 2);
- attrs[0] = talloc_strdup(attrs, "nTSecurityDescriptor");
- attrs[1] = NULL;
- parent = ldb_dn_get_parent(req, ac->dn_to_check);
- if (!is_root_base_dn(ldb, req->op.search.base) && parent && !is_root_base_dn(ldb, parent)) {
- /*we have parent so check for visibility*/
- ret = ldb_build_search_req(&ac->down_req,
- ldb, ac,
- parent,
- LDB_SCOPE_BASE,
- "(objectClass=*)",
- attrs,
- req->controls,
- ac, acl_visible_callback,
- req);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- return ldb_next_request(module, ac->down_req);
- } else {
- return acl_forward_search(ac);
+ /* What exactly to do in this case? It would fail anyway.. */
+ if ((ldb_dn_compare(req->op.rename.newdn, (ldb_get_schema_basedn(ldb))) == 0) ||
+ (ldb_dn_compare(req->op.rename.newdn, (ldb_get_config_basedn(ldb))) == 0) ||
+ (ldb_dn_compare(req->op.rename.newdn, (ldb_get_root_basedn(ldb))) == 0)) {
+ DEBUG(10,("acl:moving as an NC\n"));
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
+ /* new parent should have create child */
+ talloc_free(tmp_ctx);
+ tmp_ctx = talloc_new(req);
+ root = NULL;
+ new_node = NULL;
+ guid = get_oc_guid_from_result(module,acl_res);
+ if (!guid) {
+ DEBUG(10,("acl:renamed object has no object class\n"));
+ return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_CREATE_CHILD,
+ &root, &new_node)) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
+ ret = check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, root);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn)));
+ return ret;
+ }
+ /* do we have delete object on the object? */
- return ldb_next_request(module, req);
-}
-
-static int acl_extended(struct ldb_module *module, struct ldb_request *req)
-{
- struct ldb_context *ldb = ldb_module_get_ctx(module);
- enum security_user_level user_type;
- struct acl_private *data;
-
- data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
-
- if (!data->perform_check)
- return ldb_next_request(module, req);
+ status = sec_access_check_ds(sd, acl_user_token(module),
+ SEC_STD_DELETE,
+ &access_granted,
+ NULL);
- /* allow everybody to read the sequence number */
- if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
+ if (NT_STATUS_IS_OK(status)) {
return ldb_next_request(module, req);
}
-
- user_type = what_is_user(module);
- switch (user_type) {
- case SECURITY_SYSTEM:
- case SECURITY_ADMINISTRATOR:
- return ldb_next_request(module, req);
- default:
- ldb_asprintf_errstring(ldb,
- "acl_extended: attempted database modify not permitted."
- "User %s is not SYSTEM or an Administrator",
- user_name(req, module));
- return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ /* what about delete child on the current parent */
+ ret = check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn)));
+ return ldb_module_done(req, NULL, NULL, ret);
}
+ return ldb_next_request(module, req);
}
_PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
.name = "acl",
- .search = acl_search,
.add = acl_add,
.modify = acl_modify,
.del = acl_delete,
.rename = acl_rename,
- .extended = acl_extended,
.init_context = acl_module_init
};
diff --git a/source4/dsdb/samdb/ldb_modules/kludge_acl.c b/source4/dsdb/samdb/ldb_modules/kludge_acl.c
index 79309e82bf..0cec95b1c2 100644
--- a/source4/dsdb/samdb/ldb_modules/kludge_acl.c
+++ b/source4/dsdb/samdb/ldb_modules/kludge_acl.c
@@ -527,10 +527,10 @@ done:
_PUBLIC_ const struct ldb_module_ops ldb_kludge_acl_module_ops = {
.name = "kludge_acl",
.search = kludge_acl_search,
- .add = kludge_acl_change,
+/* .add = kludge_acl_change,
.modify = kludge_acl_change,
.del = kludge_acl_change,
- .rename = kludge_acl_change,
+ .rename = kludge_acl_change, */
.extended = kludge_acl_extended,
.init_context = kludge_acl_init
};
diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c
index a2d9792a24..3d46cfb3b1 100644
--- a/source4/dsdb/schema/schema_query.c
+++ b/source4/dsdb/schema/schema_query.c
@@ -419,8 +419,8 @@ const char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx,
/* Return the schemaIDGUID of a class */
-const struct GUID * class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
- const char *name)
+const struct GUID *class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
+ const char *name)
{
const struct dsdb_class *object_class = dsdb_class_by_lDAPDisplayName(schema, name);
if (!object_class)
@@ -428,3 +428,13 @@ const struct GUID * class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_sch
return &object_class->schemaIDGUID;
}
+
+const struct GUID *attribute_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
+ const char *name)
+{
+ const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, name);
+ if (!attr)
+ return NULL;
+
+ return &attr->schemaIDGUID;
+}
diff --git a/source4/libcli/security/object_tree.c b/source4/libcli/security/object_tree.c
index 85b407913c..7c7d644543 100644
--- a/source4/libcli/security/object_tree.c
+++ b/source4/libcli/security/object_tree.c
@@ -30,7 +30,6 @@
*/
#include "includes.h"
#include "libcli/security/security.h"
-#include "lib/util/dlinklist.h"
#include "librpc/ndr/libndr.h"
/* Adds a new node to the object tree. If attributeSecurityGUID is not zero and
@@ -38,69 +37,85 @@
* In all other cases as a child of the root
*/
-struct object_tree * insert_in_object_tree(TALLOC_CTX *mem_ctx,
- const struct GUID *schemaGUIDID,
- const struct GUID *attributeSecurityGUID,
- uint32_t init_access,
- struct object_tree *root)
+bool insert_in_object_tree(TALLOC_CTX *mem_ctx,
+ const struct GUID *guid,
+ uint32_t init_access,
+ struct object_tree **root,
+ struct object_tree **new_node)
{
- struct object_tree * parent = NULL;
- struct object_tree * new_node;
-
- new_node = talloc(mem_ctx, struct object_tree);
- if (!new_node)
- return NULL;
- memset(new_node, 0, sizeof(struct object_tree));
- new_node->remaining_access = init_access;
-
- if (!root){
- memcpy(&new_node->guid, schemaGUIDID, sizeof(struct GUID));
- return new_node;
+ if (!guid || GUID_all_zero(guid)){
+ return true;
}
- if (attributeSecurityGUID && !GUID_all_zero(attributeSecurityGUID)){
- parent = get_object_tree_by_GUID(root, attributeSecurityGUID);
- memcpy(&new_node->guid, attributeSecurityGUID, sizeof(struct GUID));
+ if (!*root){
+ *root = talloc_zero(mem_ctx, struct object_tree);
+ if (!*root) {
+ return false;
+ }
+ (*root)->guid = *guid;
+ *new_node = *root;
+ return true;
}
- else
- memcpy(&new_node->guid, schemaGUIDID, sizeof(struct GUID));
- if (!parent)
- parent = root;
-
- new_node->remaining_access = init_access;
- DLIST_ADD(parent, new_node);
- return new_node;
+ if (!(*root)->children) {
+ (*root)->children = talloc_array(mem_ctx, struct object_tree, 1);
+ (*root)->children[0].guid = *guid;
+ (*root)->children[0].num_of_children = 0;
+ (*root)->children[0].children = NULL;
+ (*root)->num_of_children++;
+ (*root)->children[0].remaining_access = init_access;
+ *new_node = &((*root)->children[0]);
+ return true;
+ }
+ else {
+ int i;
+ for (i = 0; i < (*root)->num_of_children; i++) {
+ if (GUID_equal(&((*root)->children[i].guid), guid)) {
+ *new_node = &((*root)->children[i]);
+ return true;
+ }
+ }
+ (*root)->children = talloc_realloc(mem_ctx, (*root)->children, struct object_tree,
+ (*root)->num_of_children +1);
+ (*root)->children[(*root)->num_of_children].guid = *guid;
+ (*root)->children[(*root)->num_of_children].remaining_access = init_access;
+ *new_node = &((*root)->children[(*root)->num_of_children]);
+ (*root)->num_of_children++;
+ return true;
+ }
+ return true;
}
/* search by GUID */
-struct object_tree * get_object_tree_by_GUID(struct object_tree *root,
+struct object_tree *get_object_tree_by_GUID(struct object_tree *root,
const struct GUID *guid)
{
- struct object_tree *p;
struct object_tree *result = NULL;
+ int i;
- if (!root || GUID_equal(&root->guid, guid))
+ if (!root || GUID_equal(&root->guid, guid)) {
result = root;
- else{
- for (p = root->children; p != NULL; p = p->next)
- if ((result = get_object_tree_by_GUID(p, guid)))
+ return result;
+ }
+ else if (root->num_of_children > 0) {
+ for (i = 0; i < root->num_of_children; i++) {
+ if ((result = get_object_tree_by_GUID(&root->children[i], guid)))
break;
+ }
}
-
return result;
}
/* Change the granted access per each ACE */
void object_tree_modify_access(struct object_tree *root,
- uint32_t access_mask)
+ uint32_t access)
{
- struct object_tree *p;
- if (root){
- root->remaining_access &= ~access_mask;
+ root->remaining_access &= ~access;
+ if (root->num_of_children > 0) {
+ int i;
+ for (i = 0; i < root->num_of_children; i++) {
+ object_tree_modify_access(&root->children[i], access);
+ }
}
-
- for (p = root->children; p != NULL; p = p->next)
- object_tree_modify_access(p, access_mask);
}
diff --git a/source4/libcli/security/security.h b/source4/libcli/security/security.h
index 18f6c820d1..bdf473bcf1 100644
--- a/source4/libcli/security/security.h
+++ b/source4/libcli/security/security.h
@@ -32,10 +32,8 @@ struct auth_session_info;
struct object_tree {
uint32_t remaining_access;
struct GUID guid;
- /* linked list of children */
- struct object_tree * children;
- struct object_tree * prev;
- struct object_tree * next;
+ int num_of_children;
+ struct object_tree *children;
};
/* Moved the dom_sid functions to the top level dir with manual proto header */
diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py
index 188c5909f6..ffafa2c223 100644
--- a/source4/scripting/python/samba/provision.py
+++ b/source4/scripting/python/samba/provision.py
@@ -593,7 +593,6 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
modules_list = ["resolve_oids",
"rootdse",
"lazy_commit",
- "acl",
"paged_results",
"ranged_results",
"anr",
@@ -604,6 +603,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
"rdn_name",
"objectclass",
"descriptor",
+ "acl",
"samldb",
"password_hash",
"operational",