1/* 2 ldb database library 3 4 Copyright (C) Stefan Metzmacher <metze@samba.org> 2009 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "ldb_module.h" 22#include "dsdb/samdb/samdb.h" 23 24static int resolve_oids_need_value(struct ldb_context *ldb, 25 struct dsdb_schema *schema, 26 const struct dsdb_attribute *a, 27 const struct ldb_val *valp) 28{ 29 const struct dsdb_attribute *va = NULL; 30 const struct dsdb_class *vo = NULL; 31 const void *p2; 32 char *str = NULL; 33 34 if (a->syntax->oMSyntax != 6) { 35 return LDB_ERR_COMPARE_FALSE; 36 } 37 38 if (valp) { 39 p2 = memchr(valp->data, '.', valp->length); 40 } else { 41 p2 = NULL; 42 } 43 44 if (!p2) { 45 return LDB_ERR_COMPARE_FALSE; 46 } 47 48 switch (a->attributeID_id) { 49 case DRSUAPI_ATTRIBUTE_objectClass: 50 case DRSUAPI_ATTRIBUTE_subClassOf: 51 case DRSUAPI_ATTRIBUTE_auxiliaryClass: 52 case DRSUAPI_ATTRIBUTE_systemPossSuperiors: 53 case DRSUAPI_ATTRIBUTE_possSuperiors: 54 str = talloc_strndup(ldb, (char *)valp->data, valp->length); 55 if (!str) { 56 ldb_oom(ldb); 57 return LDB_ERR_OPERATIONS_ERROR; 58 } 59 vo = dsdb_class_by_governsID_oid(schema, str); 60 talloc_free(str); 61 if (!vo) { 62 return LDB_ERR_COMPARE_FALSE; 63 } 64 return LDB_ERR_COMPARE_TRUE; 65 case DRSUAPI_ATTRIBUTE_systemMustContain: 66 case DRSUAPI_ATTRIBUTE_systemMayContain: 67 case DRSUAPI_ATTRIBUTE_mustContain: 68 case DRSUAPI_ATTRIBUTE_mayContain: 69 str = talloc_strndup(ldb, (char *)valp->data, valp->length); 70 if (!str) { 71 ldb_oom(ldb); 72 return LDB_ERR_OPERATIONS_ERROR; 73 } 74 va = dsdb_attribute_by_attributeID_oid(schema, str); 75 talloc_free(str); 76 if (!va) { 77 return LDB_ERR_COMPARE_FALSE; 78 } 79 return LDB_ERR_COMPARE_TRUE; 80 case DRSUAPI_ATTRIBUTE_governsID: 81 case DRSUAPI_ATTRIBUTE_attributeID: 82 case DRSUAPI_ATTRIBUTE_attributeSyntax: 83 return LDB_ERR_COMPARE_FALSE; 84 } 85 86 return LDB_ERR_COMPARE_FALSE; 87} 88 89static int resolve_oids_parse_tree_need(struct ldb_context *ldb, 90 struct dsdb_schema *schema, 91 const struct ldb_parse_tree *tree) 92{ 93 int i; 94 const struct dsdb_attribute *a = NULL; 95 const char *attr; 96 const char *p1; 97 const void *p2; 98 const struct ldb_val *valp = NULL; 99 int ret; 100 101 switch (tree->operation) { 102 case LDB_OP_AND: 103 case LDB_OP_OR: 104 for (i=0;i<tree->u.list.num_elements;i++) { 105 ret = resolve_oids_parse_tree_need(ldb, schema, 106 tree->u.list.elements[i]); 107 if (ret != LDB_ERR_COMPARE_FALSE) { 108 return ret; 109 } 110 } 111 return LDB_ERR_COMPARE_FALSE; 112 case LDB_OP_NOT: 113 return resolve_oids_parse_tree_need(ldb, schema, 114 tree->u.isnot.child); 115 case LDB_OP_EQUALITY: 116 case LDB_OP_GREATER: 117 case LDB_OP_LESS: 118 case LDB_OP_APPROX: 119 attr = tree->u.equality.attr; 120 valp = &tree->u.equality.value; 121 break; 122 case LDB_OP_SUBSTRING: 123 attr = tree->u.substring.attr; 124 break; 125 case LDB_OP_PRESENT: 126 attr = tree->u.present.attr; 127 break; 128 case LDB_OP_EXTENDED: 129 attr = tree->u.extended.attr; 130 valp = &tree->u.extended.value; 131 break; 132 default: 133 return LDB_ERR_COMPARE_FALSE; 134 } 135 136 p1 = strchr(attr, '.'); 137 138 if (valp) { 139 p2 = memchr(valp->data, '.', valp->length); 140 } else { 141 p2 = NULL; 142 } 143 144 if (!p1 && !p2) { 145 return LDB_ERR_COMPARE_FALSE; 146 } 147 148 if (p1) { 149 a = dsdb_attribute_by_attributeID_oid(schema, attr); 150 } else { 151 a = dsdb_attribute_by_lDAPDisplayName(schema, attr); 152 } 153 if (!a) { 154 return LDB_ERR_COMPARE_FALSE; 155 } 156 157 if (!p2) { 158 return LDB_ERR_COMPARE_FALSE; 159 } 160 161 if (a->syntax->oMSyntax != 6) { 162 return LDB_ERR_COMPARE_FALSE; 163 } 164 165 return resolve_oids_need_value(ldb, schema, a, valp); 166} 167 168static int resolve_oids_element_need(struct ldb_context *ldb, 169 struct dsdb_schema *schema, 170 const struct ldb_message_element *el) 171{ 172 int i; 173 const struct dsdb_attribute *a = NULL; 174 const char *p1; 175 176 p1 = strchr(el->name, '.'); 177 178 if (p1) { 179 a = dsdb_attribute_by_attributeID_oid(schema, el->name); 180 } else { 181 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name); 182 } 183 if (!a) { 184 return LDB_ERR_COMPARE_FALSE; 185 } 186 187 for (i=0; i < el->num_values; i++) { 188 int ret; 189 ret = resolve_oids_need_value(ldb, schema, a, 190 &el->values[i]); 191 if (ret != LDB_ERR_COMPARE_FALSE) { 192 return ret; 193 } 194 } 195 196 return LDB_ERR_COMPARE_FALSE; 197} 198 199static int resolve_oids_message_need(struct ldb_context *ldb, 200 struct dsdb_schema *schema, 201 const struct ldb_message *msg) 202{ 203 int i; 204 205 for (i=0; i < msg->num_elements; i++) { 206 int ret; 207 ret = resolve_oids_element_need(ldb, schema, 208 &msg->elements[i]); 209 if (ret != LDB_ERR_COMPARE_FALSE) { 210 return ret; 211 } 212 } 213 214 return LDB_ERR_COMPARE_FALSE; 215} 216 217static int resolve_oids_replace_value(struct ldb_context *ldb, 218 struct dsdb_schema *schema, 219 const struct dsdb_attribute *a, 220 struct ldb_val *valp) 221{ 222 const struct dsdb_attribute *va = NULL; 223 const struct dsdb_class *vo = NULL; 224 const void *p2; 225 char *str = NULL; 226 227 if (a->syntax->oMSyntax != 6) { 228 return LDB_SUCCESS; 229 } 230 231 if (valp) { 232 p2 = memchr(valp->data, '.', valp->length); 233 } else { 234 p2 = NULL; 235 } 236 237 if (!p2) { 238 return LDB_SUCCESS; 239 } 240 241 switch (a->attributeID_id) { 242 case DRSUAPI_ATTRIBUTE_objectClass: 243 case DRSUAPI_ATTRIBUTE_subClassOf: 244 case DRSUAPI_ATTRIBUTE_auxiliaryClass: 245 case DRSUAPI_ATTRIBUTE_systemPossSuperiors: 246 case DRSUAPI_ATTRIBUTE_possSuperiors: 247 str = talloc_strndup(schema, (char *)valp->data, valp->length); 248 if (!str) { 249 ldb_oom(ldb); 250 return LDB_ERR_OPERATIONS_ERROR; 251 } 252 vo = dsdb_class_by_governsID_oid(schema, str); 253 talloc_free(str); 254 if (!vo) { 255 return LDB_SUCCESS; 256 } 257 *valp = data_blob_string_const(vo->lDAPDisplayName); 258 return LDB_SUCCESS; 259 case DRSUAPI_ATTRIBUTE_systemMustContain: 260 case DRSUAPI_ATTRIBUTE_systemMayContain: 261 case DRSUAPI_ATTRIBUTE_mustContain: 262 case DRSUAPI_ATTRIBUTE_mayContain: 263 str = talloc_strndup(schema, (char *)valp->data, valp->length); 264 if (!str) { 265 ldb_oom(ldb); 266 return LDB_ERR_OPERATIONS_ERROR; 267 } 268 va = dsdb_attribute_by_attributeID_oid(schema, str); 269 talloc_free(str); 270 if (!va) { 271 return LDB_SUCCESS; 272 } 273 *valp = data_blob_string_const(va->lDAPDisplayName); 274 return LDB_SUCCESS; 275 case DRSUAPI_ATTRIBUTE_governsID: 276 case DRSUAPI_ATTRIBUTE_attributeID: 277 case DRSUAPI_ATTRIBUTE_attributeSyntax: 278 return LDB_SUCCESS; 279 } 280 281 return LDB_SUCCESS; 282} 283 284static int resolve_oids_parse_tree_replace(struct ldb_context *ldb, 285 struct dsdb_schema *schema, 286 struct ldb_parse_tree *tree) 287{ 288 int i; 289 const struct dsdb_attribute *a = NULL; 290 const char **attrp; 291 const char *p1; 292 const void *p2; 293 struct ldb_val *valp = NULL; 294 int ret; 295 296 switch (tree->operation) { 297 case LDB_OP_AND: 298 case LDB_OP_OR: 299 for (i=0;i<tree->u.list.num_elements;i++) { 300 ret = resolve_oids_parse_tree_replace(ldb, schema, 301 tree->u.list.elements[i]); 302 if (ret != LDB_SUCCESS) { 303 return ret; 304 } 305 } 306 return LDB_SUCCESS; 307 case LDB_OP_NOT: 308 return resolve_oids_parse_tree_replace(ldb, schema, 309 tree->u.isnot.child); 310 case LDB_OP_EQUALITY: 311 case LDB_OP_GREATER: 312 case LDB_OP_LESS: 313 case LDB_OP_APPROX: 314 attrp = &tree->u.equality.attr; 315 valp = &tree->u.equality.value; 316 break; 317 case LDB_OP_SUBSTRING: 318 attrp = &tree->u.substring.attr; 319 break; 320 case LDB_OP_PRESENT: 321 attrp = &tree->u.present.attr; 322 break; 323 case LDB_OP_EXTENDED: 324 attrp = &tree->u.extended.attr; 325 valp = &tree->u.extended.value; 326 break; 327 default: 328 return LDB_SUCCESS; 329 } 330 331 p1 = strchr(*attrp, '.'); 332 333 if (valp) { 334 p2 = memchr(valp->data, '.', valp->length); 335 } else { 336 p2 = NULL; 337 } 338 339 if (!p1 && !p2) { 340 return LDB_SUCCESS; 341 } 342 343 if (p1) { 344 a = dsdb_attribute_by_attributeID_oid(schema, *attrp); 345 } else { 346 a = dsdb_attribute_by_lDAPDisplayName(schema, *attrp); 347 } 348 if (!a) { 349 return LDB_SUCCESS; 350 } 351 352 *attrp = a->lDAPDisplayName; 353 354 if (!p2) { 355 return LDB_SUCCESS; 356 } 357 358 if (a->syntax->oMSyntax != 6) { 359 return LDB_SUCCESS; 360 } 361 362 return resolve_oids_replace_value(ldb, schema, a, valp); 363} 364 365static int resolve_oids_element_replace(struct ldb_context *ldb, 366 struct dsdb_schema *schema, 367 struct ldb_message_element *el) 368{ 369 int i; 370 const struct dsdb_attribute *a = NULL; 371 const char *p1; 372 373 p1 = strchr(el->name, '.'); 374 375 if (p1) { 376 a = dsdb_attribute_by_attributeID_oid(schema, el->name); 377 } else { 378 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name); 379 } 380 if (!a) { 381 return LDB_SUCCESS; 382 } 383 384 el->name = a->lDAPDisplayName; 385 386 for (i=0; i < el->num_values; i++) { 387 int ret; 388 ret = resolve_oids_replace_value(ldb, schema, a, 389 &el->values[i]); 390 if (ret != LDB_SUCCESS) { 391 return ret; 392 } 393 } 394 395 return LDB_SUCCESS; 396} 397 398static int resolve_oids_message_replace(struct ldb_context *ldb, 399 struct dsdb_schema *schema, 400 struct ldb_message *msg) 401{ 402 int i; 403 404 for (i=0; i < msg->num_elements; i++) { 405 int ret; 406 ret = resolve_oids_element_replace(ldb, schema, 407 &msg->elements[i]); 408 if (ret != LDB_SUCCESS) { 409 return ret; 410 } 411 } 412 413 return LDB_SUCCESS; 414} 415 416struct resolve_oids_context { 417 struct ldb_module *module; 418 struct ldb_request *req; 419}; 420 421static int resolve_oids_callback(struct ldb_request *req, struct ldb_reply *ares) 422{ 423 struct ldb_context *ldb; 424 struct resolve_oids_context *ac; 425 426 ac = talloc_get_type_abort(req->context, struct resolve_oids_context); 427 ldb = ldb_module_get_ctx(ac->module); 428 429 if (!ares) { 430 return ldb_module_done(ac->req, NULL, NULL, 431 LDB_ERR_OPERATIONS_ERROR); 432 } 433 if (ares->error != LDB_SUCCESS) { 434 return ldb_module_done(ac->req, ares->controls, 435 ares->response, ares->error); 436 } 437 438 switch (ares->type) { 439 case LDB_REPLY_ENTRY: 440 return ldb_module_send_entry(ac->req, ares->message, ares->controls); 441 442 case LDB_REPLY_REFERRAL: 443 return ldb_module_send_referral(ac->req, ares->referral); 444 445 case LDB_REPLY_DONE: 446 return ldb_module_done(ac->req, ares->controls, 447 ares->response, LDB_SUCCESS); 448 449 } 450 return LDB_SUCCESS; 451} 452 453static int resolve_oids_search(struct ldb_module *module, struct ldb_request *req) 454{ 455 struct ldb_context *ldb; 456 struct dsdb_schema *schema; 457 struct ldb_parse_tree *tree; 458 struct ldb_request *down_req; 459 struct resolve_oids_context *ac; 460 int ret; 461 462 ldb = ldb_module_get_ctx(module); 463 schema = dsdb_get_schema(ldb); 464 465 if (!schema) { 466 return ldb_next_request(module, req); 467 } 468 469 /* do not manipulate our control entries */ 470 if (ldb_dn_is_special(req->op.search.base)) { 471 return ldb_next_request(module, req); 472 } 473 474 ret = resolve_oids_parse_tree_need(ldb, schema, 475 req->op.search.tree); 476 if (ret == LDB_ERR_COMPARE_FALSE) { 477 return ldb_next_request(module, req); 478 } else if (ret != LDB_ERR_COMPARE_TRUE) { 479 return ret; 480 } 481 482 ac = talloc(req, struct resolve_oids_context); 483 if (ac == NULL) { 484 ldb_oom(ldb); 485 return LDB_ERR_OPERATIONS_ERROR; 486 } 487 ac->module = module; 488 ac->req = req; 489 490 tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree); 491 if (!tree) { 492 ldb_oom(ldb); 493 return LDB_ERR_OPERATIONS_ERROR; 494 } 495 496 ret = resolve_oids_parse_tree_replace(ldb, schema, 497 tree); 498 if (ret != LDB_SUCCESS) { 499 return ret; 500 } 501 502 ret = ldb_build_search_req_ex(&down_req, ldb, ac, 503 req->op.search.base, 504 req->op.search.scope, 505 tree, 506 req->op.search.attrs, 507 req->controls, 508 ac, resolve_oids_callback, 509 req); 510 if (ret != LDB_SUCCESS) { 511 return ret; 512 } 513 514 /* go on with the call chain */ 515 return ldb_next_request(module, down_req); 516} 517 518static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req) 519{ 520 struct ldb_context *ldb; 521 struct dsdb_schema *schema; 522 int ret; 523 struct ldb_message *msg; 524 struct ldb_request *down_req; 525 struct resolve_oids_context *ac; 526 527 ldb = ldb_module_get_ctx(module); 528 schema = dsdb_get_schema(ldb); 529 530 if (!schema) { 531 return ldb_next_request(module, req); 532 } 533 534 /* do not manipulate our control entries */ 535 if (ldb_dn_is_special(req->op.add.message->dn)) { 536 return ldb_next_request(module, req); 537 } 538 539 ret = resolve_oids_message_need(ldb, schema, 540 req->op.add.message); 541 if (ret == LDB_ERR_COMPARE_FALSE) { 542 return ldb_next_request(module, req); 543 } else if (ret != LDB_ERR_COMPARE_TRUE) { 544 return ret; 545 } 546 547 ac = talloc(req, struct resolve_oids_context); 548 if (ac == NULL) { 549 ldb_oom(ldb); 550 return LDB_ERR_OPERATIONS_ERROR; 551 } 552 ac->module = module; 553 ac->req = req; 554 555 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message); 556 if (!msg) { 557 ldb_oom(ldb); 558 return LDB_ERR_OPERATIONS_ERROR; 559 } 560 561 ret = resolve_oids_message_replace(ldb, schema, msg); 562 if (ret != LDB_SUCCESS) { 563 return ret; 564 } 565 566 ret = ldb_build_add_req(&down_req, ldb, ac, 567 msg, 568 req->controls, 569 ac, resolve_oids_callback, 570 req); 571 if (ret != LDB_SUCCESS) { 572 return ret; 573 } 574 575 /* go on with the call chain */ 576 return ldb_next_request(module, down_req); 577} 578 579static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req) 580{ 581 struct ldb_context *ldb; 582 struct dsdb_schema *schema; 583 int ret; 584 struct ldb_message *msg; 585 struct ldb_request *down_req; 586 struct resolve_oids_context *ac; 587 588 ldb = ldb_module_get_ctx(module); 589 schema = dsdb_get_schema(ldb); 590 591 if (!schema) { 592 return ldb_next_request(module, req); 593 } 594 595 /* do not manipulate our control entries */ 596 if (ldb_dn_is_special(req->op.mod.message->dn)) { 597 return ldb_next_request(module, req); 598 } 599 600 ret = resolve_oids_message_need(ldb, schema, 601 req->op.mod.message); 602 if (ret == LDB_ERR_COMPARE_FALSE) { 603 return ldb_next_request(module, req); 604 } else if (ret != LDB_ERR_COMPARE_TRUE) { 605 return ret; 606 } 607 608 ac = talloc(req, struct resolve_oids_context); 609 if (ac == NULL) { 610 ldb_oom(ldb); 611 return LDB_ERR_OPERATIONS_ERROR; 612 } 613 ac->module = module; 614 ac->req = req; 615 616 /* we have to copy the message as the caller might have it as a const */ 617 msg = ldb_msg_copy_shallow(ac, req->op.mod.message); 618 if (msg == NULL) { 619 ldb_oom(ldb); 620 return LDB_ERR_OPERATIONS_ERROR; 621 } 622 623 ret = resolve_oids_message_replace(ldb, schema, msg); 624 if (ret != LDB_SUCCESS) { 625 return ret; 626 } 627 628 ret = ldb_build_mod_req(&down_req, ldb, ac, 629 msg, 630 req->controls, 631 ac, resolve_oids_callback, 632 req); 633 if (ret != LDB_SUCCESS) { 634 return ret; 635 } 636 637 /* go on with the call chain */ 638 return ldb_next_request(module, down_req); 639} 640 641_PUBLIC_ const struct ldb_module_ops ldb_resolve_oids_module_ops = { 642 .name = "resolve_oids", 643 .search = resolve_oids_search, 644 .add = resolve_oids_add, 645 .modify = resolve_oids_modify, 646}; 647 648