summaryrefslogtreecommitdiff
path: root/source4
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 /source4
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.
Diffstat (limited to 'source4')
-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",