1/* 2 ldb database library 3 4 Copyright (C) Simo Sorce 2006-2008 5 Copyright (C) Nadezhda Ivanova 2009 6 Copyright (C) Anatoliy Atanasov 2009 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22/* 23 * Name: ldb 24 * 25 * Component: ldb ACL module 26 * 27 * Description: Module that performs authorisation access checks based on the 28 * account's security context and the DACL of the object being polled. 29 * Only DACL checks implemented at this point 30 * 31 * Authors: Nadezhda Ivanova, Anatoliy Atanasov 32 */ 33 34#include "includes.h" 35#include "ldb_module.h" 36#include "auth/auth.h" 37#include "libcli/security/security.h" 38#include "librpc/gen_ndr/ndr_security.h" 39#include "dsdb/samdb/samdb.h" 40#include "librpc/gen_ndr/ndr_security.h" 41#include "param/param.h" 42 43/* acl_search helper */ 44struct acl_context { 45 46 struct ldb_module *module; 47 struct ldb_request *req; 48 struct ldb_request *down_req; 49 50 /*needed if we have to identify if this is SYSTEM_USER*/ 51 enum security_user_level user_type; 52 53 uint32_t access_needed; 54 struct ldb_dn * dn_to_check; 55 56 /* set to true when we need to process the request as a SYSTEM_USER, regardless 57 * of the user's actual rights - for example when we need to retrieve the 58 * ntSecurityDescriptor */ 59 bool ignore_security; 60 struct security_token *token; 61 /*needed to identify if we have requested these attributes*/ 62 bool nTSecurityDescriptor; 63 bool objectClass; 64 int sec_result; 65}; 66 67struct extended_access_check_attribute { 68 const char *oa_name; 69 const uint32_t requires_rights; 70}; 71 72struct acl_private{ 73 bool perform_check; 74}; 75 76static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares); 77 78/*FIXME: Perhaps this should go in the .idl file*/ 79#define SEC_GENERIC_ACCESS_NEVER_GRANTED ( 0xFFFFFFFF ) 80 81/*Contains a part of the attributes - the ones that have predefined required rights*/ 82static const struct extended_access_check_attribute extended_access_checks_table[] = 83{ 84 { 85 .oa_name = "nTSecurityDescriptor", 86 .requires_rights = SEC_FLAG_SYSTEM_SECURITY & SEC_STD_READ_CONTROL, 87 }, 88 { 89 .oa_name = "pekList", 90 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 91 }, 92 { 93 .oa_name = "currentValue", 94 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 95 }, 96 { 97 .oa_name = "dBCSPwd", 98 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 99 }, 100 { 101 .oa_name = "unicodePwd", 102 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 103 }, 104 { 105 .oa_name = "ntPwdHistory", 106 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 107 }, 108 { 109 .oa_name = "priorValue", 110 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 111 }, 112 { 113 .oa_name = "supplementalCredentials", 114 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 115 }, 116 { 117 .oa_name = "trustAuthIncoming", 118 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 119 }, 120 { 121 .oa_name = "trustAuthOutgoing", 122 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 123 }, 124 { 125 .oa_name = "ImPwdHistory", 126 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 127 }, 128 { 129 .oa_name = "initialAuthIncoming", 130 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 131 }, 132 { 133 .oa_name = "initialAuthOutgoing", 134 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 135 }, 136 { 137 .oa_name = "msDS-ExecuteScriptPassword", 138 .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED, 139 }, 140}; 141 142static NTSTATUS extended_access_check(const char *attribute_name, const int access_rights, uint32_t searchFlags) 143{ 144 int i = 0; 145 if (access_rights == SEC_GENERIC_ACCESS_NEVER_GRANTED) { 146 return NT_STATUS_ACCESS_DENIED; 147 } 148 149 /*Check if the attribute is in the table first*/ 150 for ( i = 0; extended_access_checks_table[i].oa_name; i++ ) { 151 if (ldb_attr_cmp(extended_access_checks_table[i].oa_name, attribute_name) == 0) { 152 if ((access_rights & extended_access_checks_table[i].requires_rights) == access_rights) { 153 return NT_STATUS_OK; 154 } else { 155 return NT_STATUS_ACCESS_DENIED; 156 } 157 } 158 } 159 160 /*Check for attribute whose attributeSchema has 0x80 set in searchFlags*/ 161 if ((searchFlags & SEARCH_FLAG_CONFIDENTIAL) == SEARCH_FLAG_CONFIDENTIAL) { 162 if (((SEC_ADS_READ_PROP & SEC_ADS_CONTROL_ACCESS) & access_rights) == access_rights) { 163 return NT_STATUS_OK; 164 } else { 165 return NT_STATUS_ACCESS_DENIED; 166 } 167 } 168 169 /*Check attributes with *special* behaviour*/ 170 if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0 || ldb_attr_cmp("msDS-QuotaUsed", attribute_name) == 0){ 171 /*Rights required: 172 * 173 *(RIGHT_DS_READ_PROPERTY on the Quotas container or 174 *((the client is querying the quota for the security principal it is authenticated as) and 175 *(DS-Query-Self-Quota control access right on the Quotas container)) 176 */ 177 } 178 179 if (ldb_attr_cmp("userPassword", attribute_name) == 0) { 180 /*When the dSHeuristics.fUserPwdSupport flag is false, the requester must be granted RIGHT_DS_READ_PROPERTY. 181 *When the dSHeuristics.fUserPwdSupport flag is true, access is never granted. 182 */ 183 } 184 185 if (ldb_attr_cmp("sDRightsEffective", attribute_name) == 0) { 186 /*FIXME:3.1.1.4.5.4 in MS-ADTS*/ 187 } 188 189 if (ldb_attr_cmp("allowedChildClassesEffective", attribute_name) == 0) { 190 /*FIXME:3.1.1.4.5.5 in MS-ADTS*/ 191 } 192 193 if (ldb_attr_cmp("allowedAttributesEffective", attribute_name) == 0) { 194 /*FIXME:3.1.1.4.5.7 in MS-ADTS*/ 195 } 196 197 if (ldb_attr_cmp("msDS-Approx-Immed-Subordinates", attribute_name) == 0) { 198 /*FIXME:3.1.1.4.5.15 in MS-ADTS*/ 199 } 200 201 if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0) { 202 /*FIXME:3.1.1.4.5.22 in MS-ADTS*/ 203 } 204 205 if (ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0 || ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0) { 206 /*The security context of the requester must be granted the following rights on the replPropertyMetaData attribute: 207 *(RIGHT_DS_READ_PROPERTY)or (DS-Replication-Manage-Topology by ON!nTSecurityDescriptor) 208 */ 209 } 210 211 if (ldb_attr_cmp("msDS-NCReplInboundNeighbors", attribute_name) == 0) { 212 /*The security context of the requester must be granted the following rights on repsFrom: 213 *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology) 214 */ 215 } 216 217 if (ldb_attr_cmp("msDS-NCReplOutboundNeighbors", attribute_name) == 0) { 218 /*The security context of the requester must be granted the following rights on repsTo: 219 *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology) 220 */ 221 } 222 223 if (ldb_attr_cmp("msDS-NCReplCursors", attribute_name) == 0) { 224 /*The security context of the requester must be granted the following rights on replUpToDateVector: (RIGHT_DS_READ_PROPERTY) 225 *or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology) 226 */ 227 } 228 229 if (ldb_attr_cmp("msDS-IsUserCachableAtRodc", attribute_name) == 0) { 230 /*The security context of the requester must be granted 231 *the DS-Replication-Secrets-Synchronize control access right on the root of the default NC. 232 */ 233 } 234 235 return NT_STATUS_OK; 236} 237 238/* Builds an object tree for object specific access checks */ 239static struct object_tree * build_object_tree_form_attr_list(TALLOC_CTX *mem_ctx, /* Todo this context or separate? */ 240 struct ldb_context *ldb, 241 const char ** attr_names, 242 int num_attrs, 243 const char * object_class, 244 uint32_t init_access) 245{ 246 const struct dsdb_schema *schema = dsdb_get_schema(ldb); 247 const struct GUID *oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, object_class); 248 struct object_tree *tree; 249 int i; 250 251 if (!oc_guid) 252 return NULL; 253 254 tree = insert_in_object_tree(mem_ctx, oc_guid, NULL, init_access, NULL); 255 if (attr_names){ 256 for (i=0; i < num_attrs; i++){ 257 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema,attr_names[i]); 258 if (attribute) 259 insert_in_object_tree(mem_ctx, 260 &attribute->schemaIDGUID, 261 &attribute->attributeSecurityGUID, 262 init_access, 263 tree); 264 } 265 } 266 return tree; 267} 268 269bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check) 270{ 271 int result; 272 struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb); 273 result = ldb_dn_compare(root_base_dn,dn_to_check); 274 return (result==0); 275} 276 277static int acl_op_callback(struct ldb_request *req, struct ldb_reply *ares) 278{ 279 struct acl_context *ac; 280 281 ac = talloc_get_type(req->context, struct acl_context); 282 283 if (!ares) { 284 return ldb_module_done(ac->req, NULL, NULL, 285 LDB_ERR_OPERATIONS_ERROR); 286 } 287 if (ares->error != LDB_SUCCESS) { 288 return ldb_module_done(ac->req, ares->controls, 289 ares->response, ares->error); 290 } 291 292 if (ares->type != LDB_REPLY_DONE) { 293 talloc_free(ares); 294 return ldb_module_done(ac->req, NULL, NULL, 295 LDB_ERR_OPERATIONS_ERROR); 296 } 297 298 return ldb_module_done(ac->req, ares->controls, 299 ares->response, ares->error); 300} 301 302 303static int acl_access_check_add(struct ldb_reply *ares, 304 struct acl_context *ac, 305 struct security_descriptor *sd) 306{ 307 uint32_t access_granted = 0; 308 NTSTATUS status; 309 struct ldb_dn *parent; 310 struct ldb_dn *grandparent; 311 struct object_tree *tree = NULL; 312 313 parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn); 314 grandparent = ldb_dn_get_parent(ac->req, parent); 315 if (ldb_dn_compare(ares->message->dn, grandparent) == 0) 316 status = sec_access_check_ds(sd, ac->token, 317 SEC_ADS_LIST, 318 &access_granted, 319 NULL); 320 else if (ldb_dn_compare(ares->message->dn, parent) == 0){ 321 struct ldb_message_element *oc_el; 322 struct ldb_context *ldb = ldb_module_get_ctx(ac->module); 323 const struct dsdb_schema *schema = dsdb_get_schema(ldb); 324 int i; 325 326 oc_el = ldb_msg_find_element(ares->message, "objectClass"); 327 if (!oc_el || oc_el->num_values == 0) 328 return LDB_SUCCESS; 329 for (i = 0; i < oc_el->num_values; i++){ 330 const struct GUID *guid = class_schemaid_guid_by_lDAPDisplayName(schema, 331 oc_el->values[i].data); 332 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; 333 tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_CREATE_CHILD, 334 tree); 335 status = sec_access_check_ds(sd, ac->token, SEC_ADS_CREATE_CHILD,&access_granted, tree); 336 if (NT_STATUS_IS_OK(status)) 337 ac->sec_result = LDB_SUCCESS; 338 } 339 } 340 else 341 return LDB_SUCCESS; 342 343 return ac->sec_result; 344} 345 346static int acl_access_check_modify(struct ldb_reply *ares, struct acl_context *ac, 347 struct security_descriptor *sd) 348{ 349 uint32_t access_granted = 0; 350 NTSTATUS status; 351 struct ldb_dn *parent; 352 struct object_tree *tree = NULL; 353 354 parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn); 355 if (ldb_dn_compare(ares->message->dn, parent) == 0) 356 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL); 357 else if (ldb_dn_compare(ares->message->dn, ac->req->op.add.message->dn) == 0){ 358 struct ldb_message_element *oc_el; 359 struct ldb_context *ldb = ldb_module_get_ctx(ac->module); 360 const struct dsdb_schema *schema = dsdb_get_schema(ldb); 361 int i; 362 struct GUID *guid; 363 oc_el = ldb_msg_find_element(ares->message, "objectClass"); 364 if (!oc_el || oc_el->num_values == 0) 365 return LDB_SUCCESS; 366 367 guid = class_schemaid_guid_by_lDAPDisplayName(schema, 368 oc_el->values[oc_el->num_values-1].data); 369 tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_WRITE_PROP, 370 tree); 371 for (i=0; i < ac->req->op.mod.message->num_elements; i++){ 372 const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, 373 ac->req->op.mod.message->elements[i].name); 374 if (!attr) 375 return LDB_ERR_OPERATIONS_ERROR; /* What should we actually return here? */ 376 insert_in_object_tree(ac, &attr->schemaIDGUID, 377 &attr->attributeSecurityGUID, ac->access_needed, tree); 378 } 379 status = sec_access_check_ds(sd, ac->token, SEC_ADS_WRITE_PROP ,&access_granted, tree); 380 if (!NT_STATUS_IS_OK(status)) 381 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; 382 } 383 else 384 return LDB_SUCCESS; 385 return ac->sec_result; 386} 387/*TODO*/ 388static int acl_access_check_rename(struct ldb_reply *ares, struct acl_context *ac, 389 struct security_descriptor *sd) 390{ 391 return ac->sec_result; 392} 393 394static int acl_access_check_delete(struct ldb_reply *ares, struct acl_context *ac, 395 struct security_descriptor *sd) 396{ 397 uint32_t access_granted = 0; 398 NTSTATUS status; 399 struct ldb_dn *parent; 400 struct object_tree *tree = NULL; 401 402 parent = ldb_dn_get_parent(ac->req, ac->req->op.del.dn); 403 if (ldb_dn_compare(ares->message->dn, parent) == 0){ 404 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL); 405 if (!NT_STATUS_IS_OK(status)){ 406 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; 407 return ac->sec_result; 408 } 409 status = sec_access_check_ds(sd, ac->token, SEC_ADS_DELETE_CHILD,&access_granted, NULL); 410 if (NT_STATUS_IS_OK(status)){ 411 ac->sec_result = LDB_SUCCESS; 412 return ac->sec_result; 413 } 414 } 415 else if (ldb_dn_compare(ares->message->dn, ac->req->op.del.dn) == 0){ 416 status = sec_access_check_ds(sd, ac->token, SEC_STD_DELETE, &access_granted, NULL); 417 if (!NT_STATUS_IS_OK(status)) 418 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; 419 } 420 return ac->sec_result; 421} 422 423static int acl_access_check_search(struct ldb_reply *ares, struct acl_context *ac, 424 struct security_descriptor *sd) 425{ 426 uint32_t access_granted; 427 NTSTATUS status; 428 struct ldb_dn *parent; 429 430 if (ac->user_type == SECURITY_SYSTEM || ac->user_type == SECURITY_ANONYMOUS) { 431 return LDB_SUCCESS;/*FIXME: we have anonymous access*/ 432 } 433 434 parent = ldb_dn_get_parent(ac->req, ac->dn_to_check); 435 ac->sec_result = LDB_SUCCESS; 436 if (ldb_dn_compare(ares->message->dn, parent) == 0) { 437 status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL); 438 if (!NT_STATUS_IS_OK(status)) { 439 ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; 440 } 441 } 442 443 return ac->sec_result; 444} 445 446static int acl_perform_access_check(struct ldb_request *req, struct ldb_reply *ares, 447 struct acl_context *ac) 448{ 449 struct ldb_message_element *oc_el; 450 struct security_descriptor *sd; 451 enum ndr_err_code ndr_err; 452 453 oc_el = ldb_msg_find_element(ares->message, "ntSecurityDescriptor"); 454 if (!oc_el || oc_el->num_values == 0) 455 return LDB_SUCCESS; 456 457 sd = talloc(ac, struct security_descriptor); 458 if(!sd) { 459 return ldb_module_done(ac->req, ares->controls, 460 ares->response, LDB_ERR_OPERATIONS_ERROR); 461 } 462 ndr_err = ndr_pull_struct_blob(&oc_el->values[0], sd, NULL, sd, 463 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); 464 465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) 466 return ldb_module_done(ac->req, ares->controls, 467 ares->response, LDB_ERR_OPERATIONS_ERROR); 468 switch (ac->req->operation) { 469 case LDB_SEARCH: 470 return acl_access_check_search(ares, ac, sd); 471 case LDB_ADD: 472 return acl_access_check_add(ares, ac, sd); 473 case LDB_MODIFY: 474 return acl_access_check_modify(ares, ac, sd); 475 case LDB_DELETE: 476 return acl_access_check_delete(ares, ac, sd); 477 case LDB_RENAME: 478 return acl_access_check_rename(ares, ac, sd); 479 default: 480 return ldb_module_done(ac->req, ares->controls, 481 ares->response, LDB_ERR_OPERATIONS_ERROR); 482 } 483 return LDB_SUCCESS; 484} 485 486static int acl_forward_add(struct ldb_reply *ares, 487 struct acl_context *ac) 488{ 489 struct ldb_request *newreq; 490 struct ldb_context *ldb; 491 int ret; 492 493 ldb = ldb_module_get_ctx(ac->module); 494 ret = ldb_build_add_req(&newreq,ldb, 495 ac, 496 ac->req->op.add.message, 497 ac->req->controls, 498 ac, 499 acl_op_callback, 500 ac->req); 501 if (ret != LDB_SUCCESS) 502 return ldb_module_done(ac->req, ares->controls, 503 ares->response, LDB_ERR_OPERATIONS_ERROR); 504 return ldb_next_request(ac->module, newreq); 505} 506 507static int acl_forward_modify(struct ldb_reply *ares, 508 struct acl_context *ac) 509{ 510 struct ldb_request *newreq; 511 struct ldb_context *ldb; 512 int ret; 513 514 ldb = ldb_module_get_ctx(ac->module); 515 ret = ldb_build_mod_req(&newreq,ldb, 516 ac, 517 ac->req->op.mod.message, 518 ac->req->controls, 519 ac, 520 acl_op_callback, 521 ac->req); 522 if (ret != LDB_SUCCESS) 523 return ldb_module_done(ac->req, ares->controls, 524 ares->response, LDB_ERR_OPERATIONS_ERROR); 525 return ldb_next_request(ac->module, newreq); 526} 527 528static int acl_forward_delete(struct ldb_reply *ares, 529 struct acl_context *ac) 530{ 531 struct ldb_request *newreq; 532 struct ldb_context *ldb; 533 int ret; 534 535 ldb = ldb_module_get_ctx(ac->module); 536 ret = ldb_build_del_req(&newreq, ldb, 537 ac, 538 ac->req->op.del.dn, 539 ac->req->controls, 540 ac, 541 acl_op_callback, 542 ac->req); 543 if (ret != LDB_SUCCESS) 544 return ldb_module_done(ac->req, ares->controls, 545 ares->response, LDB_ERR_OPERATIONS_ERROR); 546 return ldb_next_request(ac->module, newreq); 547} 548 549static int acl_forward_rename(struct ldb_reply *ares, 550 struct acl_context *ac) 551{ 552 return LDB_SUCCESS; 553} 554 555static int acl_forward_search(struct acl_context *ac) 556{ 557 int ret; 558 const char * const *attrs; 559 struct ldb_control *sd_control; 560 struct ldb_control **sd_saved_controls; 561 struct ldb_context *ldb; 562 struct ldb_request *newreq; 563 564 ldb = ldb_module_get_ctx(ac->module); 565 attrs = ac->req->op.search.attrs; 566 if (attrs) { 567 ac->nTSecurityDescriptor = false; 568 ac->objectClass = false; 569 if (!ldb_attr_in_list(ac->req->op.search.attrs, "nTSecurityDescriptor")) { 570 attrs = ldb_attr_list_copy_add(ac, attrs, "nTSecurityDescriptor"); 571 ac->nTSecurityDescriptor = true; 572 } 573 if (!ldb_attr_in_list(ac->req->op.search.attrs, "objectClass")) { 574 attrs = ldb_attr_list_copy_add(ac, attrs, "objectClass"); 575 ac->objectClass = true; 576 } 577 } 578 ret = ldb_build_search_req_ex(&newreq,ldb, 579 ac, 580 ac->req->op.search.base, 581 ac->req->op.search.scope, 582 ac->req->op.search.tree, 583 attrs, 584 ac->req->controls, 585 ac, acl_search_callback, 586 ac->req); 587 if (ret != LDB_SUCCESS) { 588 return LDB_ERR_OPERATIONS_ERROR; 589 } 590 /* check if there's an SD_FLAGS control */ 591 sd_control = ldb_request_get_control(newreq, LDB_CONTROL_SD_FLAGS_OID); 592 if (sd_control) { 593 /* save it locally and remove it from the list */ 594 /* we do not need to replace them later as we 595 * are keeping the original req intact */ 596 if (!save_controls(sd_control, newreq, &sd_saved_controls)) { 597 return LDB_ERR_OPERATIONS_ERROR; 598 } 599 } 600 return ldb_next_request(ac->module, newreq); 601} 602 603static int acl_forward_request(struct ldb_reply *ares, 604 struct acl_context *ac) 605{ 606 switch (ac->req->operation) { 607 case LDB_SEARCH: 608 return acl_forward_search(ac); 609 case LDB_ADD: 610 return acl_forward_add(ares,ac); 611 case LDB_MODIFY: 612 return acl_forward_modify(ares,ac); 613 case LDB_DELETE: 614 return acl_forward_delete(ares,ac); 615 case LDB_RENAME: 616 return acl_forward_rename(ares,ac); 617 default: 618 return ldb_module_done(ac->req, ares->controls, 619 ares->response, LDB_ERR_OPERATIONS_ERROR); 620 } 621 return LDB_SUCCESS; 622} 623 624static int acl_visible_callback(struct ldb_request *req, struct ldb_reply *ares) 625{ 626 struct acl_context *ac; 627 628 ac = talloc_get_type(req->context, struct acl_context); 629 630 if (!ares) { 631 return ldb_module_done(ac->req, NULL, NULL, 632 LDB_ERR_OPERATIONS_ERROR); 633 } 634 635 if (ares->error != LDB_SUCCESS) { 636 return ldb_module_done(ac->req, ares->controls, 637 ares->response, ares->error); 638 } 639 640 switch (ares->type) { 641 case LDB_REPLY_ENTRY: 642 return acl_perform_access_check(req, ares, ac); 643 case LDB_REPLY_REFERRAL: 644 return ldb_module_send_referral(ac->req, ares->referral); /* what to do here actually? */ 645 case LDB_REPLY_DONE: 646 if (ac->sec_result != LDB_SUCCESS) { 647 return ldb_module_done(ac->req, ares->controls, 648 ares->response, ac->sec_result); 649 } 650 return acl_forward_request(ares,ac); 651 default: 652 break; 653 } 654 return LDB_SUCCESS; 655} 656 657static enum security_user_level what_is_user(struct ldb_module *module) 658{ 659 struct ldb_context *ldb = ldb_module_get_ctx(module); 660 struct auth_session_info *session_info 661 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); 662 return security_session_user_level(session_info); 663} 664 665static struct security_token * user_token(struct ldb_module *module) 666{ 667 struct ldb_context *ldb = ldb_module_get_ctx(module); 668 struct auth_session_info *session_info 669 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); 670 if(!session_info) { 671 return NULL; 672 } 673 return session_info->security_token; 674} 675 676 677static int make_req_access_check(struct ldb_module *module, struct ldb_request *req, 678 struct acl_context *ac, const char *filter) 679{ 680 struct ldb_context *ldb; 681 int ret; 682 const char **attrs = talloc_array(ac, const char *, 3); 683 struct ldb_parse_tree *tree = ldb_parse_tree(req, filter); 684 685 attrs[0] = talloc_strdup(attrs, "ntSecurityDescriptor"); 686 attrs[1] = talloc_strdup(attrs, "objectClass"); 687 attrs[2] = NULL; 688 689 ldb = ldb_module_get_ctx(module); 690 ret = ldb_build_search_req_ex(&ac->down_req, 691 ldb, ac, 692 ac->dn_to_check, 693 LDB_SCOPE_SUBTREE, 694 tree, 695 attrs, 696 NULL, 697 ac, acl_visible_callback, 698 req); 699 return ret; 700} 701 702static const char *user_name(TALLOC_CTX *mem_ctx, struct ldb_module *module) 703{ 704 struct ldb_context *ldb = ldb_module_get_ctx(module); 705 struct auth_session_info *session_info 706 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); 707 if (!session_info) { 708 return "UNKNOWN (NULL)"; 709 } 710 711 return talloc_asprintf(mem_ctx, "%s\\%s", 712 session_info->server_info->domain_name, 713 session_info->server_info->account_name); 714} 715 716static int acl_module_init(struct ldb_module *module) 717{ 718 struct ldb_context *ldb; 719 struct acl_private *data; 720 int ret; 721 722 ldb = ldb_module_get_ctx(module); 723 724 ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID); 725 if (ret != LDB_SUCCESS) { 726 ldb_debug(ldb, LDB_DEBUG_ERROR, 727 "acl_module_init: Unable to register control with rootdse!\n"); 728 return LDB_ERR_OPERATIONS_ERROR; 729 } 730 731 data = talloc(module, struct acl_private); 732 data->perform_check = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"), 733 NULL, "acl", "perform", false); 734 ldb_module_set_private(module, data); 735 736 return ldb_next_init(module); 737} 738 739static int acl_add(struct ldb_module *module, struct ldb_request *req) 740{ 741 int ret; 742 struct acl_context *ac; 743 struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.add.message->dn); 744 char * filter; 745 struct ldb_context *ldb; 746 struct acl_private *data; 747 748 ldb = ldb_module_get_ctx(module); 749 data = talloc_get_type(ldb_module_get_private(module), struct acl_private); 750 751 if (!data->perform_check) 752 return ldb_next_request(module, req); 753 754 ac = talloc(req, struct acl_context); 755 if (ac == NULL) { 756 return LDB_ERR_OPERATIONS_ERROR; 757 } 758 759 if (what_is_user(module) == SECURITY_SYSTEM) 760 return ldb_next_request(module, req); 761 762 ac->module = module; 763 ac->req = req; 764 ac->ignore_security = true; 765 ac->dn_to_check = ldb_dn_get_parent(req, parent); 766 ac->token = user_token(module); 767 ac->user_type = what_is_user(module); 768 ac->sec_result = LDB_SUCCESS; 769 if (!is_root_base_dn(ldb, req->op.add.message->dn) && parent && !is_root_base_dn(ldb, parent)){ 770 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))", 771 ldb_dn_get_component_name(parent,0), 772 ldb_dn_get_component_val(parent,0)->data, 773 ldb_dn_get_component_name(ac->dn_to_check,0), 774 ldb_dn_get_component_val(ac->dn_to_check,0)->data); 775 776 ret = make_req_access_check(module, req, ac, filter); 777 if (ret != LDB_SUCCESS){ 778 return ret; 779 } 780 return ldb_next_request(module, ac->down_req); 781 } 782 return ldb_next_request(module, req); 783} 784 785static int acl_modify(struct ldb_module *module, struct ldb_request *req) 786{ 787 int ret; 788 struct acl_context *ac; 789 struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.mod.message->dn); 790 char * filter; 791 struct ldb_context *ldb; 792 struct acl_private *data; 793 794 ldb = ldb_module_get_ctx(module); 795 data = talloc_get_type(ldb_module_get_private(module), struct acl_private); 796 797 if (!data->perform_check) 798 return ldb_next_request(module, req); 799 800 ac = talloc(req, struct acl_context); 801 if (ac == NULL) { 802 return LDB_ERR_OPERATIONS_ERROR; 803 } 804 805/* if (what_is_user(module) == SECURITY_SYSTEM) */ 806 return ldb_next_request(module, req); 807 808 ac->module = module; 809 ac->req = req; 810 ac->ignore_security = true; 811 ac->dn_to_check = req->op.mod.message->dn; 812 ac->token = user_token(module); 813 ac->user_type = what_is_user(module); 814 ac->sec_result = LDB_SUCCESS; 815 if (!is_root_base_dn(ldb, req->op.mod.message->dn) && parent && !is_root_base_dn(ldb, parent)){ 816 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))", 817 ldb_dn_get_component_name(parent,0), 818 ldb_dn_get_component_val(parent,0)->data, 819 ldb_dn_get_component_name(req->op.mod.message->dn,0), 820 ldb_dn_get_component_val(req->op.mod.message->dn,0)->data); 821 822 ret = make_req_access_check(module, req, ac, filter); 823 if (ret != LDB_SUCCESS){ 824 return ret; 825 } 826 return ldb_next_request(module, ac->down_req); 827 } 828 return ldb_next_request(module, req); 829} 830 831/* similar to the modify for the time being. 832 * We need to concider the special delete tree case, though - TODO */ 833static int acl_delete(struct ldb_module *module, struct ldb_request *req) 834{ 835 int ret; 836 struct acl_context *ac; 837 struct ldb_dn * parent = ldb_dn_get_parent(req, req->op.del.dn); 838 char * filter; 839 struct ldb_context *ldb; 840 struct acl_private *data; 841 842 ldb = ldb_module_get_ctx(module); 843 data = talloc_get_type(ldb_module_get_private(module), struct acl_private); 844 845 if (!data->perform_check) 846 return ldb_next_request(module, req); 847 848 ac = talloc(req, struct acl_context); 849 if (ac == NULL) { 850 return LDB_ERR_OPERATIONS_ERROR; 851 } 852 853 if (ac->user_type == SECURITY_SYSTEM) 854 return ldb_next_request(module, req); 855 856 ac->module = module; 857 ac->req = req; 858 ac->ignore_security = true; 859 ac->dn_to_check = req->op.del.dn; 860 ac->token = user_token(module); 861 ac->user_type = what_is_user(module); 862 ac->sec_result = LDB_SUCCESS; 863 if (parent) { 864 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))", 865 ldb_dn_get_component_name(parent,0), 866 ldb_dn_get_component_val(parent,0)->data, 867 ldb_dn_get_component_name(req->op.del.dn,0), 868 ldb_dn_get_component_val(req->op.del.dn,0)->data); 869 ret = make_req_access_check(module, req, ac, filter); 870 871 if (ret != LDB_SUCCESS){ 872 return ret; 873 } 874 return ldb_next_request(module, ac->down_req); 875 } 876 877 return ldb_next_request(module, req); 878} 879 880static int acl_rename(struct ldb_module *module, struct ldb_request *req) 881{ 882 struct ldb_dn *source_parent; 883 struct ldb_dn *dest_parent; 884 int ret; 885 struct acl_context *ac; 886 char * filter; 887 struct ldb_context *ldb; 888 struct acl_private *data; 889 890 ldb = ldb_module_get_ctx(module); 891 data = talloc_get_type(ldb_module_get_private(module), struct acl_private); 892 893 if (!data->perform_check) 894 return ldb_next_request(module, req); 895 896 ac = talloc(req, struct acl_context); 897 if (ac == NULL) { 898 return LDB_ERR_OPERATIONS_ERROR; 899 } 900 901 if (ac->user_type == SECURITY_SYSTEM) 902 return ldb_next_request(module, req); 903 904 ac->module = module; 905 ac->req = req; 906 ac->ignore_security = true; 907 ac->token = user_token(module); 908 ac->user_type = what_is_user(module); 909 ac->sec_result = LDB_SUCCESS; 910 911 /* We need to know if it is a simple rename or a move operation */ 912 source_parent = ldb_dn_get_parent(req, req->op.rename.olddn); 913 dest_parent = ldb_dn_get_parent(req, req->op.rename.newdn); 914 915 if (ldb_dn_compare(source_parent, dest_parent) == 0){ 916 /*Not a move, just rename*/ 917 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))", 918 ldb_dn_get_component_name(dest_parent,0), 919 ldb_dn_get_component_val(dest_parent,0)->data, 920 ldb_dn_get_component_name(req->op.rename.olddn,0), 921 ldb_dn_get_component_val(req->op.rename.olddn,0)->data); 922 } 923 else{ 924 filter = talloc_asprintf(req,"(&(objectClass=*)(|(%s=%s)(%s=%s))))", 925 ldb_dn_get_component_name(dest_parent,0), 926 ldb_dn_get_component_val(dest_parent,0)->data, 927 ldb_dn_get_component_name(source_parent,0), 928 ldb_dn_get_component_val(source_parent,0)->data); 929 } 930 931 ret = make_req_access_check(module, req, ac, filter); 932 933 if (ret != LDB_SUCCESS){ 934 return ret; 935 } 936 return ldb_next_request(module, ac->down_req); 937} 938 939static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares) 940{ 941 struct ldb_context *ldb; 942 struct acl_context *ac; 943 struct security_descriptor *sd; 944 uint32_t searchFlags; 945 uint32_t access_mask; 946 struct object_tree *ot; 947 int i, ret; 948 NTSTATUS status; 949 struct ldb_message_element *element_security_descriptor; 950 struct ldb_message_element *element_object_class; 951 const struct dsdb_attribute *attr; 952 const struct dsdb_schema *schema; 953 struct GUID *oc_guid; 954 955 ac = talloc_get_type(req->context, struct acl_context); 956 ldb = ldb_module_get_ctx(ac->module); 957 schema = dsdb_get_schema(ldb); 958 if (!ares) { 959 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); 960 } 961 if (ares->error != LDB_SUCCESS) { 962 return ldb_module_done(ac->req, ares->controls, ares->response, ares->error); 963 } 964 965 switch (ares->type) { 966 case LDB_REPLY_ENTRY: 967 switch (ac->user_type) { 968 case SECURITY_SYSTEM: 969 case SECURITY_ANONYMOUS:/*FIXME: should we let anonymous have system access*/ 970 break; 971 default: 972 /* Access checks 973 * 974 * 0. If we do not have nTSecurityDescriptor, we do not have an object in the response, 975 * so check the parent dn. 976 * 1. Call sec_access_check on empty tree 977 * 2. For each attribute call extended_access_check 978 * 3. For each attribute call build_object_tree_form_attr_list and then check with sec_access_check 979 * 980 */ 981 element_security_descriptor = ldb_msg_find_element(ares->message, "nTSecurityDescriptor"); 982 element_object_class = ldb_msg_find_element(ares->message, "objectClass"); 983 if (!element_security_descriptor || !element_object_class) 984 break; 985 986 sd = talloc(ldb, struct security_descriptor); 987 if(!sd) { 988 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); 989 } 990 if(!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&element_security_descriptor->values[0], 991 ldb, 992 NULL, 993 sd, 994 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) { 995 DEBUG(0, ("acl_search_callback: Error parsing security descriptor\n")); 996 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); 997 } 998 999 oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, element_object_class->values[0].data); 1000 for (i=0; i<ares->message->num_elements; i++) { 1001 attr = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name); 1002 if (attr) { 1003 searchFlags = attr->searchFlags; 1004 } else { 1005 searchFlags = 0x0; 1006 } 1007 1008 /*status = extended_access_check(ares->message->elements[i].name, access_mask, searchFlags); */ /* Todo FIXME */ 1009 ac->access_needed = SEC_ADS_READ_PROP; 1010 if (NT_STATUS_IS_OK(status)) { 1011 ot = insert_in_object_tree(req, oc_guid, NULL, ac->access_needed, NULL); 1012 1013 insert_in_object_tree(req, 1014 &attr->schemaIDGUID, 1015 &attr->attributeSecurityGUID, 1016 ac->access_needed, 1017 ot); 1018 1019 status = sec_access_check_ds(sd, 1020 ac->token, 1021 ac->access_needed, 1022 &access_mask, 1023 ot); 1024 1025 if (NT_STATUS_IS_OK(status)) { 1026 continue; 1027 } 1028 } 1029 ldb_msg_remove_attr(ares->message, ares->message->elements[i].name); 1030 } 1031 break; 1032 } 1033 if (ac->nTSecurityDescriptor) { 1034 ldb_msg_remove_attr(ares->message, "nTSecurityDescriptor"); 1035 } else if (ac->objectClass) { 1036 ldb_msg_remove_attr(ares->message, "objectClass"); 1037 } 1038 1039 return ldb_module_send_entry(ac->req, ares->message, ares->controls); 1040 case LDB_REPLY_REFERRAL: 1041 return ldb_module_send_referral(ac->req, ares->referral); 1042 1043 case LDB_REPLY_DONE: 1044 return ldb_module_done(ac->req, ares->controls,ares->response, LDB_SUCCESS); 1045 } 1046 1047 return LDB_SUCCESS; 1048} 1049 1050static int acl_search(struct ldb_module *module, struct ldb_request *req) 1051{ 1052 int ret; 1053 struct ldb_context *ldb; 1054 struct acl_context *ac; 1055 const char **attrs; 1056 struct ldb_control *sd_control; 1057 struct ldb_control **sd_saved_controls; 1058 struct ldb_dn * parent; 1059 struct acl_private *data; 1060 1061 ldb = ldb_module_get_ctx(module); 1062 data = talloc_get_type(ldb_module_get_private(module), struct acl_private); 1063 1064 if (!data || !data->perform_check) 1065 return ldb_next_request(module, req); 1066 1067 if (what_is_user(module) == SECURITY_SYSTEM) 1068 return ldb_next_request(module, req); 1069 1070 ac = talloc_get_type(req->context, struct acl_context); 1071 if ( ac == NULL ) { 1072 ac = talloc(req, struct acl_context); 1073 if (ac == NULL) { 1074 ldb_oom(ldb); 1075 return LDB_ERR_OPERATIONS_ERROR; 1076 } 1077 ac->module = module; 1078 ac->req = req; 1079 ac->ignore_security = false; 1080 ac->user_type = what_is_user(module); 1081 ac->token = user_token(module); 1082 ac->dn_to_check = req->op.search.base; 1083 ac->sec_result = LDB_SUCCESS; 1084 1085 attrs = talloc_array(ac, const char*, 2); 1086 attrs[0] = talloc_strdup(attrs, "nTSecurityDescriptor"); 1087 attrs[1] = NULL; 1088 parent = ldb_dn_get_parent(req, ac->dn_to_check); 1089 if (!is_root_base_dn(ldb, req->op.search.base) && parent && !is_root_base_dn(ldb, parent)) { 1090 /*we have parent so check for visibility*/ 1091 ret = ldb_build_search_req(&ac->down_req, 1092 ldb, ac, 1093 parent, 1094 LDB_SCOPE_BASE, 1095 "(objectClass=*)", 1096 attrs, 1097 req->controls, 1098 ac, acl_visible_callback, 1099 req); 1100 if (ret != LDB_SUCCESS) { 1101 return ret; 1102 } 1103 return ldb_next_request(module, ac->down_req); 1104 } else { 1105 return acl_forward_search(ac); 1106 } 1107 } 1108 1109 return ldb_next_request(module, req); 1110} 1111 1112static int acl_extended(struct ldb_module *module, struct ldb_request *req) 1113{ 1114 struct ldb_context *ldb = ldb_module_get_ctx(module); 1115 enum security_user_level user_type; 1116 struct acl_private *data; 1117 1118 data = talloc_get_type(ldb_module_get_private(module), struct acl_private); 1119 1120 if (!data->perform_check) 1121 return ldb_next_request(module, req); 1122 1123 /* allow everybody to read the sequence number */ 1124 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) { 1125 return ldb_next_request(module, req); 1126 } 1127 1128 user_type = what_is_user(module); 1129 switch (user_type) { 1130 case SECURITY_SYSTEM: 1131 case SECURITY_ADMINISTRATOR: 1132 return ldb_next_request(module, req); 1133 default: 1134 ldb_asprintf_errstring(ldb, 1135 "acl_extended: attempted database modify not permitted." 1136 "User %s is not SYSTEM or an Administrator", 1137 user_name(req, module)); 1138 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; 1139 } 1140} 1141 1142_PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = { 1143 .name = "acl", 1144 .search = acl_search, 1145 .add = acl_add, 1146 .modify = acl_modify, 1147 .del = acl_delete, 1148 .rename = acl_rename, 1149 .extended = acl_extended, 1150 .init_context = acl_module_init 1151}; 1152