1/* 2 ldb database library - ldif handlers for Samba 3 4 Copyright (C) Andrew Tridgell 2005 5 Copyright (C) Andrew Bartlett 2006-2007 6 Copyright (C) Matthias Dieter Walln��fer 2009 7 ** NOTE! The following LGPL license applies to the ldb 8 ** library. This does NOT imply that all of Samba is released 9 ** under the LGPL 10 11 This library is free software; you can redistribute it and/or 12 modify it under the terms of the GNU Lesser General Public 13 License as published by the Free Software Foundation; either 14 version 3 of the License, or (at your option) any later version. 15 16 This library is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 Lesser General Public License for more details. 20 21 You should have received a copy of the GNU Lesser General Public 22 License along with this library; if not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#include "includes.h" 26#include "lib/ldb/include/ldb.h" 27#include "lib/ldb/include/ldb_module.h" 28#include "ldb_handlers.h" 29#include "dsdb/samdb/samdb.h" 30#include "librpc/gen_ndr/ndr_security.h" 31#include "librpc/gen_ndr/ndr_misc.h" 32#include "librpc/gen_ndr/ndr_drsblobs.h" 33#include "librpc/ndr/libndr.h" 34#include "libcli/security/security.h" 35#include "param/param.h" 36 37/* 38 use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob 39*/ 40static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx, 41 const struct ldb_val *in, struct ldb_val *out, 42 size_t struct_size, 43 ndr_pull_flags_fn_t pull_fn, 44 ndr_print_fn_t print_fn) 45{ 46 uint8_t *p; 47 enum ndr_err_code err; 48 if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) { 49 return ldb_handler_copy(ldb, mem_ctx, in, out); 50 } 51 p = talloc_size(mem_ctx, struct_size); 52 err = ndr_pull_struct_blob(in, mem_ctx, 53 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 54 p, pull_fn); 55 if (err != NDR_ERR_SUCCESS) { 56 talloc_free(p); 57 out->data = (uint8_t *)talloc_strdup(mem_ctx, "<Unable to decode binary data>"); 58 out->length = strlen((const char *)out->data); 59 return 0; 60 } 61 out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p); 62 talloc_free(p); 63 if (out->data == NULL) { 64 return ldb_handler_copy(ldb, mem_ctx, in, out); 65 } 66 out->length = strlen((char *)out->data); 67 return 0; 68} 69 70/* 71 convert a ldif formatted objectSid to a NDR formatted blob 72*/ 73static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx, 74 const struct ldb_val *in, struct ldb_val *out) 75{ 76 enum ndr_err_code ndr_err; 77 struct dom_sid *sid; 78 sid = dom_sid_parse_length(mem_ctx, in); 79 if (sid == NULL) { 80 return -1; 81 } 82 ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sid, 83 (ndr_push_flags_fn_t)ndr_push_dom_sid); 84 talloc_free(sid); 85 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 86 return -1; 87 } 88 return 0; 89} 90 91/* 92 convert a NDR formatted blob to a ldif formatted objectSid 93*/ 94static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx, 95 const struct ldb_val *in, struct ldb_val *out) 96{ 97 struct dom_sid *sid; 98 enum ndr_err_code ndr_err; 99 100 sid = talloc(mem_ctx, struct dom_sid); 101 if (sid == NULL) { 102 return -1; 103 } 104 ndr_err = ndr_pull_struct_blob_all(in, sid, NULL, sid, 105 (ndr_pull_flags_fn_t)ndr_pull_dom_sid); 106 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 107 talloc_free(sid); 108 return -1; 109 } 110 *out = data_blob_string_const(dom_sid_string(mem_ctx, sid)); 111 talloc_free(sid); 112 if (out->data == NULL) { 113 return -1; 114 } 115 return 0; 116} 117 118static bool ldif_comparision_objectSid_isString(const struct ldb_val *v) 119{ 120 if (v->length < 3) { 121 return false; 122 } 123 124 if (strncmp("S-", (const char *)v->data, 2) != 0) return false; 125 126 return true; 127} 128 129/* 130 compare two objectSids 131*/ 132static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx, 133 const struct ldb_val *v1, const struct ldb_val *v2) 134{ 135 if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) { 136 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 137 } else if (ldif_comparision_objectSid_isString(v1) 138 && !ldif_comparision_objectSid_isString(v2)) { 139 struct ldb_val v; 140 int ret; 141 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) { 142 /* Perhaps not a string after all */ 143 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 144 } 145 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2); 146 talloc_free(v.data); 147 return ret; 148 } else if (!ldif_comparision_objectSid_isString(v1) 149 && ldif_comparision_objectSid_isString(v2)) { 150 struct ldb_val v; 151 int ret; 152 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) { 153 /* Perhaps not a string after all */ 154 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 155 } 156 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v); 157 talloc_free(v.data); 158 return ret; 159 } 160 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 161} 162 163/* 164 canonicalise a objectSid 165*/ 166static int ldif_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx, 167 const struct ldb_val *in, struct ldb_val *out) 168{ 169 if (ldif_comparision_objectSid_isString(in)) { 170 if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) { 171 /* Perhaps not a string after all */ 172 return ldb_handler_copy(ldb, mem_ctx, in, out); 173 } 174 return 0; 175 } 176 return ldb_handler_copy(ldb, mem_ctx, in, out); 177} 178 179static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx, 180 const struct ldb_val *in, struct ldb_val *out) 181{ 182 struct dom_sid sid; 183 enum ndr_err_code ndr_err; 184 if (ldif_comparision_objectSid_isString(in)) { 185 if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) { 186 return 0; 187 } 188 } 189 190 /* Perhaps not a string after all */ 191 *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1); 192 193 if (!out->data) { 194 return -1; 195 } 196 197 (*out).length = strhex_to_str((char *)out->data, out->length, 198 (const char *)in->data, in->length); 199 200 /* Check it looks like a SID */ 201 ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &sid, 202 (ndr_pull_flags_fn_t)ndr_pull_dom_sid); 203 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 204 return -1; 205 } 206 return 0; 207} 208 209/* 210 convert a ldif formatted objectGUID to a NDR formatted blob 211*/ 212static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx, 213 const struct ldb_val *in, struct ldb_val *out) 214{ 215 struct GUID guid; 216 NTSTATUS status; 217 enum ndr_err_code ndr_err; 218 219 status = GUID_from_data_blob(in, &guid); 220 if (!NT_STATUS_IS_OK(status)) { 221 return -1; 222 } 223 224 ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, &guid, 225 (ndr_push_flags_fn_t)ndr_push_GUID); 226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 227 return -1; 228 } 229 return 0; 230} 231 232/* 233 convert a NDR formatted blob to a ldif formatted objectGUID 234*/ 235static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx, 236 const struct ldb_val *in, struct ldb_val *out) 237{ 238 struct GUID guid; 239 enum ndr_err_code ndr_err; 240 ndr_err = ndr_pull_struct_blob_all(in, mem_ctx, NULL, &guid, 241 (ndr_pull_flags_fn_t)ndr_pull_GUID); 242 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 243 return -1; 244 } 245 out->data = (uint8_t *)GUID_string(mem_ctx, &guid); 246 if (out->data == NULL) { 247 return -1; 248 } 249 out->length = strlen((const char *)out->data); 250 return 0; 251} 252 253static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v) 254{ 255 if (v->length != 36 && v->length != 38) return false; 256 257 /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */ 258 return true; 259} 260 261static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx, 262 const struct ldb_val *in, struct ldb_val *out) 263{ 264 struct GUID guid; 265 enum ndr_err_code ndr_err; 266 if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) { 267 return 0; 268 } 269 270 /* Try as 'hex' form */ 271 if (in->length != 32) { 272 return -1; 273 } 274 275 *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1); 276 277 if (!out->data) { 278 return -1; 279 } 280 281 (*out).length = strhex_to_str((char *)out->data, out->length, 282 (const char *)in->data, in->length); 283 284 /* Check it looks like a GUID */ 285 ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &guid, 286 (ndr_pull_flags_fn_t)ndr_pull_GUID); 287 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 288 return -1; 289 } 290 return 0; 291} 292 293/* 294 compare two objectGUIDs 295*/ 296static int ldif_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx, 297 const struct ldb_val *v1, const struct ldb_val *v2) 298{ 299 if (ldif_comparision_objectGUID_isString(v1) && ldif_comparision_objectGUID_isString(v2)) { 300 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 301 } else if (ldif_comparision_objectGUID_isString(v1) 302 && !ldif_comparision_objectGUID_isString(v2)) { 303 struct ldb_val v; 304 int ret; 305 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) { 306 /* Perhaps it wasn't a valid string after all */ 307 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 308 } 309 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2); 310 talloc_free(v.data); 311 return ret; 312 } else if (!ldif_comparision_objectGUID_isString(v1) 313 && ldif_comparision_objectGUID_isString(v2)) { 314 struct ldb_val v; 315 int ret; 316 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) { 317 /* Perhaps it wasn't a valid string after all */ 318 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 319 } 320 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v); 321 talloc_free(v.data); 322 return ret; 323 } 324 return ldb_comparison_binary(ldb, mem_ctx, v1, v2); 325} 326 327/* 328 canonicalise a objectGUID 329*/ 330static int ldif_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx, 331 const struct ldb_val *in, struct ldb_val *out) 332{ 333 if (ldif_comparision_objectGUID_isString(in)) { 334 if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) { 335 /* Perhaps it wasn't a valid string after all */ 336 return ldb_handler_copy(ldb, mem_ctx, in, out); 337 } 338 return 0; 339 } 340 return ldb_handler_copy(ldb, mem_ctx, in, out); 341} 342 343 344/* 345 convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob 346*/ 347static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx, 348 const struct ldb_val *in, struct ldb_val *out) 349{ 350 struct security_descriptor *sd; 351 enum ndr_err_code ndr_err; 352 353 sd = talloc(mem_ctx, struct security_descriptor); 354 if (sd == NULL) { 355 return -1; 356 } 357 358 ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd, 359 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); 360 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 361 /* If this does not parse, then it is probably SDDL, and we should try it that way */ 362 363 const struct dom_sid *sid = samdb_domain_sid(ldb); 364 talloc_free(sd); 365 sd = sddl_decode(mem_ctx, (const char *)in->data, sid); 366 if (sd == NULL) { 367 return -1; 368 } 369 } 370 371 ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd, 372 (ndr_push_flags_fn_t)ndr_push_security_descriptor); 373 talloc_free(sd); 374 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 375 return -1; 376 } 377 378 return 0; 379} 380 381/* 382 convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format) 383*/ 384static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx, 385 const struct ldb_val *in, struct ldb_val *out) 386{ 387 struct security_descriptor *sd; 388 enum ndr_err_code ndr_err; 389 390 if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) { 391 return ldif_write_NDR(ldb, mem_ctx, in, out, 392 sizeof(struct security_descriptor), 393 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor, 394 (ndr_print_fn_t)ndr_print_security_descriptor); 395 396 } 397 398 sd = talloc(mem_ctx, struct security_descriptor); 399 if (sd == NULL) { 400 return -1; 401 } 402 /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */ 403 ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd, 404 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); 405 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 406 talloc_free(sd); 407 return -1; 408 } 409 out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL); 410 talloc_free(sd); 411 if (out->data == NULL) { 412 return -1; 413 } 414 out->length = strlen((const char *)out->data); 415 return 0; 416} 417 418/* 419 canonicalise an objectCategory. We use the short form as the cannoical form: 420 cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person' 421*/ 422 423static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx, 424 const struct ldb_val *in, struct ldb_val *out) 425{ 426 struct ldb_dn *dn1 = NULL; 427 const struct dsdb_schema *schema = dsdb_get_schema(ldb); 428 const struct dsdb_class *sclass; 429 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 430 if (!tmp_ctx) { 431 return LDB_ERR_OPERATIONS_ERROR; 432 } 433 434 if (!schema) { 435 talloc_free(tmp_ctx); 436 *out = data_blob_talloc(mem_ctx, in->data, in->length); 437 if (in->data && !out->data) { 438 return LDB_ERR_OPERATIONS_ERROR; 439 } 440 return LDB_SUCCESS; 441 } 442 dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in); 443 if ( ! ldb_dn_validate(dn1)) { 444 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length); 445 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName); 446 if (sclass) { 447 struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, 448 sclass->defaultObjectCategory); 449 *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn)); 450 talloc_free(tmp_ctx); 451 452 if (!out->data) { 453 return LDB_ERR_OPERATIONS_ERROR; 454 } 455 return LDB_SUCCESS; 456 } else { 457 *out = data_blob_talloc(mem_ctx, in->data, in->length); 458 talloc_free(tmp_ctx); 459 460 if (in->data && !out->data) { 461 return LDB_ERR_OPERATIONS_ERROR; 462 } 463 return LDB_SUCCESS; 464 } 465 } 466 *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1)); 467 talloc_free(tmp_ctx); 468 469 if (!out->data) { 470 return LDB_ERR_OPERATIONS_ERROR; 471 } 472 return LDB_SUCCESS; 473} 474 475static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx, 476 const struct ldb_val *v1, 477 const struct ldb_val *v2) 478{ 479 480 int ret, ret1, ret2; 481 struct ldb_val v1_canon, v2_canon; 482 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 483 484 /* I could try and bail if tmp_ctx was NULL, but what return 485 * value would I use? 486 * 487 * It seems easier to continue on the NULL context 488 */ 489 ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon); 490 ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon); 491 492 if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) { 493 ret = data_blob_cmp(&v1_canon, &v2_canon); 494 } else { 495 ret = data_blob_cmp(v1, v2); 496 } 497 talloc_free(tmp_ctx); 498 return ret; 499} 500 501/* 502 convert a ldif formatted prefixMap to a NDR formatted blob 503*/ 504static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx, 505 const struct ldb_val *in, struct ldb_val *out) 506{ 507 struct prefixMapBlob *blob; 508 enum ndr_err_code ndr_err; 509 char *string, *line, *p, *oid; 510 511 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 512 513 if (tmp_ctx == NULL) { 514 return -1; 515 } 516 517 blob = talloc_zero(tmp_ctx, struct prefixMapBlob); 518 if (blob == NULL) { 519 talloc_free(blob); 520 return -1; 521 } 522 523 blob->version = PREFIX_MAP_VERSION_DSDB; 524 525 string = talloc_strndup(mem_ctx, (const char *)in->data, in->length); 526 if (string == NULL) { 527 talloc_free(blob); 528 return -1; 529 } 530 531 line = string; 532 while (line && line[0]) { 533 p=strchr(line, ';'); 534 if (p) { 535 p[0] = '\0'; 536 } else { 537 p=strchr(line, '\n'); 538 if (p) { 539 p[0] = '\0'; 540 } 541 } 542 /* allow a traling seperator */ 543 if (line == p) { 544 break; 545 } 546 547 blob->ctr.dsdb.mappings = talloc_realloc(blob, 548 blob->ctr.dsdb.mappings, 549 struct drsuapi_DsReplicaOIDMapping, 550 blob->ctr.dsdb.num_mappings+1); 551 if (!blob->ctr.dsdb.mappings) { 552 talloc_free(tmp_ctx); 553 return -1; 554 } 555 556 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10); 557 558 if (oid[0] != ':') { 559 talloc_free(tmp_ctx); 560 return -1; 561 } 562 563 /* we know there must be at least ":" */ 564 oid++; 565 566 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid 567 = talloc_strdup(blob->ctr.dsdb.mappings, oid); 568 569 blob->ctr.dsdb.num_mappings++; 570 571 /* Now look past the terminator we added above */ 572 if (p) { 573 line = p + 1; 574 } else { 575 line = NULL; 576 } 577 } 578 579 ndr_err = ndr_push_struct_blob(out, mem_ctx, 580 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 581 blob, 582 (ndr_push_flags_fn_t)ndr_push_prefixMapBlob); 583 talloc_free(tmp_ctx); 584 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 585 return -1; 586 } 587 return 0; 588} 589 590/* 591 convert a NDR formatted blob to a ldif formatted prefixMap 592*/ 593static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx, 594 const struct ldb_val *in, struct ldb_val *out) 595{ 596 struct prefixMapBlob *blob; 597 enum ndr_err_code ndr_err; 598 char *string; 599 uint32_t i; 600 601 if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) { 602 return ldif_write_NDR(ldb, mem_ctx, in, out, 603 sizeof(struct prefixMapBlob), 604 (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob, 605 (ndr_print_fn_t)ndr_print_prefixMapBlob); 606 607 } 608 609 blob = talloc(mem_ctx, struct prefixMapBlob); 610 if (blob == NULL) { 611 return -1; 612 } 613 ndr_err = ndr_pull_struct_blob_all(in, blob, 614 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 615 blob, 616 (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob); 617 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 618 talloc_free(blob); 619 return -1; 620 } 621 if (blob->version != PREFIX_MAP_VERSION_DSDB) { 622 return -1; 623 } 624 string = talloc_strdup(mem_ctx, ""); 625 if (string == NULL) { 626 return -1; 627 } 628 629 for (i=0; i < blob->ctr.dsdb.num_mappings; i++) { 630 if (i > 0) { 631 string = talloc_asprintf_append(string, ";"); 632 } 633 string = talloc_asprintf_append(string, "%u:%s", 634 blob->ctr.dsdb.mappings[i].id_prefix, 635 blob->ctr.dsdb.mappings[i].oid.oid); 636 if (string == NULL) { 637 return -1; 638 } 639 } 640 641 talloc_free(blob); 642 *out = data_blob_string_const(string); 643 return 0; 644} 645 646static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v) 647{ 648 if (v->length < 4) { 649 return true; 650 } 651 652 if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) { 653 return false; 654 } 655 656 return true; 657} 658 659/* 660 canonicalise a prefixMap 661*/ 662static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx, 663 const struct ldb_val *in, struct ldb_val *out) 664{ 665 if (ldif_comparision_prefixMap_isString(in)) { 666 return ldif_read_prefixMap(ldb, mem_ctx, in, out); 667 } 668 return ldb_handler_copy(ldb, mem_ctx, in, out); 669} 670 671static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx, 672 const struct ldb_val *v1, 673 const struct ldb_val *v2) 674{ 675 676 int ret, ret1, ret2; 677 struct ldb_val v1_canon, v2_canon; 678 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 679 680 /* I could try and bail if tmp_ctx was NULL, but what return 681 * value would I use? 682 * 683 * It seems easier to continue on the NULL context 684 */ 685 ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon); 686 ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon); 687 688 if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) { 689 ret = data_blob_cmp(&v1_canon, &v2_canon); 690 } else { 691 ret = data_blob_cmp(v1, v2); 692 } 693 talloc_free(tmp_ctx); 694 return ret; 695} 696 697/* Canonicalisation of two 32-bit integers */ 698static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx, 699 const struct ldb_val *in, struct ldb_val *out) 700{ 701 char *end; 702 /* We've to use "strtoll" here to have the intended overflows. 703 * Otherwise we may get "LONG_MAX" and the conversion is wrong. */ 704 int32_t i = (int32_t) strtoll((char *)in->data, &end, 0); 705 if (*end != 0) { 706 return -1; 707 } 708 out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i); 709 if (out->data == NULL) { 710 return -1; 711 } 712 out->length = strlen((char *)out->data); 713 return 0; 714} 715 716/* Comparison of two 32-bit integers */ 717static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx, 718 const struct ldb_val *v1, const struct ldb_val *v2) 719{ 720 /* We've to use "strtoll" here to have the intended overflows. 721 * Otherwise we may get "LONG_MAX" and the conversion is wrong. */ 722 return (int32_t) strtoll((char *)v1->data, NULL, 0) 723 - (int32_t) strtoll((char *)v2->data, NULL, 0); 724} 725 726/* 727 convert a NDR formatted blob to a ldif formatted repsFromTo 728*/ 729static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx, 730 const struct ldb_val *in, struct ldb_val *out) 731{ 732 return ldif_write_NDR(ldb, mem_ctx, in, out, 733 sizeof(struct repsFromToBlob), 734 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob, 735 (ndr_print_fn_t)ndr_print_repsFromToBlob); 736} 737 738/* 739 convert a NDR formatted blob to a ldif formatted replPropertyMetaData 740*/ 741static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx, 742 const struct ldb_val *in, struct ldb_val *out) 743{ 744 return ldif_write_NDR(ldb, mem_ctx, in, out, 745 sizeof(struct replPropertyMetaDataBlob), 746 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob, 747 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob); 748} 749 750/* 751 convert a NDR formatted blob to a ldif formatted replUpToDateVector 752*/ 753static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx, 754 const struct ldb_val *in, struct ldb_val *out) 755{ 756 return ldif_write_NDR(ldb, mem_ctx, in, out, 757 sizeof(struct replUpToDateVectorBlob), 758 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob, 759 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob); 760} 761 762 763static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx, 764 const struct ldb_val *in, struct ldb_val *out) 765{ 766 *out = data_blob_string_const(data_blob_hex_string(mem_ctx, in)); 767 if (!out->data) { 768 return -1; 769 } 770 return 0; 771} 772 773static const struct ldb_schema_syntax samba_syntaxes[] = { 774 { 775 .name = LDB_SYNTAX_SAMBA_SID, 776 .ldif_read_fn = ldif_read_objectSid, 777 .ldif_write_fn = ldif_write_objectSid, 778 .canonicalise_fn = ldif_canonicalise_objectSid, 779 .comparison_fn = ldif_comparison_objectSid 780 },{ 781 .name = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR, 782 .ldif_read_fn = ldif_read_ntSecurityDescriptor, 783 .ldif_write_fn = ldif_write_ntSecurityDescriptor, 784 .canonicalise_fn = ldb_handler_copy, 785 .comparison_fn = ldb_comparison_binary 786 },{ 787 .name = LDB_SYNTAX_SAMBA_GUID, 788 .ldif_read_fn = ldif_read_objectGUID, 789 .ldif_write_fn = ldif_write_objectGUID, 790 .canonicalise_fn = ldif_canonicalise_objectGUID, 791 .comparison_fn = ldif_comparison_objectGUID 792 },{ 793 .name = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY, 794 .ldif_read_fn = ldb_handler_copy, 795 .ldif_write_fn = ldb_handler_copy, 796 .canonicalise_fn = ldif_canonicalise_objectCategory, 797 .comparison_fn = ldif_comparison_objectCategory 798 },{ 799 .name = LDB_SYNTAX_SAMBA_PREFIX_MAP, 800 .ldif_read_fn = ldif_read_prefixMap, 801 .ldif_write_fn = ldif_write_prefixMap, 802 .canonicalise_fn = ldif_canonicalise_prefixMap, 803 .comparison_fn = ldif_comparison_prefixMap 804 },{ 805 .name = LDB_SYNTAX_SAMBA_INT32, 806 .ldif_read_fn = ldb_handler_copy, 807 .ldif_write_fn = ldb_handler_copy, 808 .canonicalise_fn = ldif_canonicalise_int32, 809 .comparison_fn = ldif_comparison_int32 810 },{ 811 .name = LDB_SYNTAX_SAMBA_REPSFROMTO, 812 .ldif_read_fn = ldb_handler_copy, 813 .ldif_write_fn = ldif_write_repsFromTo, 814 .canonicalise_fn = ldb_handler_copy, 815 .comparison_fn = ldb_comparison_binary 816 },{ 817 .name = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA, 818 .ldif_read_fn = ldb_handler_copy, 819 .ldif_write_fn = ldif_write_replPropertyMetaData, 820 .canonicalise_fn = ldb_handler_copy, 821 .comparison_fn = ldb_comparison_binary 822 },{ 823 .name = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR, 824 .ldif_read_fn = ldb_handler_copy, 825 .ldif_write_fn = ldif_write_replUpToDateVector, 826 .canonicalise_fn = ldb_handler_copy, 827 .comparison_fn = ldb_comparison_binary 828 }, 829}; 830 831static const struct ldb_dn_extended_syntax samba_dn_syntax[] = { 832 { 833 .name = "SID", 834 .read_fn = extended_dn_read_SID, 835 .write_clear_fn = ldif_write_objectSid, 836 .write_hex_fn = extended_dn_write_hex 837 },{ 838 .name = "GUID", 839 .read_fn = extended_dn_read_GUID, 840 .write_clear_fn = ldif_write_objectGUID, 841 .write_hex_fn = extended_dn_write_hex 842 },{ 843 .name = "WKGUID", 844 .read_fn = ldb_handler_copy, 845 .write_clear_fn = ldb_handler_copy, 846 .write_hex_fn = ldb_handler_copy 847 } 848}; 849 850/* TODO: Should be dynamic at some point */ 851static const struct { 852 const char *name; 853 const char *syntax; 854} samba_attributes[] = { 855 { "objectSid", LDB_SYNTAX_SAMBA_SID }, 856 { "securityIdentifier", LDB_SYNTAX_SAMBA_SID }, 857 { "ntSecurityDescriptor", LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR }, 858 { "objectGUID", LDB_SYNTAX_SAMBA_GUID }, 859 { "invocationId", LDB_SYNTAX_SAMBA_GUID }, 860 { "schemaIDGUID", LDB_SYNTAX_SAMBA_GUID }, 861 { "attributeSecurityGUID", LDB_SYNTAX_SAMBA_GUID }, 862 { "parentGUID", LDB_SYNTAX_SAMBA_GUID }, 863 { "siteGUID", LDB_SYNTAX_SAMBA_GUID }, 864 { "pKTGUID", LDB_SYNTAX_SAMBA_GUID }, 865 { "fRSVersionGUID", LDB_SYNTAX_SAMBA_GUID }, 866 { "fRSReplicaSetGUID", LDB_SYNTAX_SAMBA_GUID }, 867 { "netbootGUID", LDB_SYNTAX_SAMBA_GUID }, 868 { "objectCategory", LDB_SYNTAX_SAMBA_OBJECT_CATEGORY }, 869 { "prefixMap", LDB_SYNTAX_SAMBA_PREFIX_MAP }, 870 { "repsFrom", LDB_SYNTAX_SAMBA_REPSFROMTO }, 871 { "repsTo", LDB_SYNTAX_SAMBA_REPSFROMTO }, 872 { "replPropertyMetaData", LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA }, 873 { "replUpToDateVector", LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR }, 874}; 875 876const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name) 877{ 878 uint32_t j; 879 const struct ldb_schema_syntax *s = NULL; 880 881 for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) { 882 if (strcmp(name, samba_syntaxes[j].name) == 0) { 883 s = &samba_syntaxes[j]; 884 break; 885 } 886 } 887 return s; 888} 889 890const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name) 891{ 892 uint32_t j; 893 const struct ldb_schema_syntax *s = NULL; 894 895 for (j=0; j < ARRAY_SIZE(samba_attributes); j++) { 896 if (strcmp(samba_attributes[j].name, name) == 0) { 897 s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax); 898 break; 899 } 900 } 901 902 return s; 903} 904 905/* 906 register the samba ldif handlers 907*/ 908int ldb_register_samba_handlers(struct ldb_context *ldb) 909{ 910 uint32_t i; 911 912 for (i=0; i < ARRAY_SIZE(samba_attributes); i++) { 913 int ret; 914 const struct ldb_schema_syntax *s = NULL; 915 916 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax); 917 918 if (!s) { 919 s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax); 920 } 921 922 if (!s) { 923 return -1; 924 } 925 926 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s); 927 if (ret != LDB_SUCCESS) { 928 return ret; 929 } 930 } 931 932 for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) { 933 int ret; 934 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]); 935 if (ret != LDB_SUCCESS) { 936 return ret; 937 } 938 939 940 } 941 942 return LDB_SUCCESS; 943} 944