Changeset 740 for vendor/current/source4/dsdb/common
- Timestamp:
- Nov 14, 2012, 12:59:34 PM (13 years ago)
- Location:
- vendor/current/source4/dsdb/common
- Files:
-
- 8 added
- 1 deleted
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source4/dsdb/common/util.c
r414 r740 25 25 #include "events/events.h" 26 26 #include "ldb.h" 27 #include "ldb_module.h" 27 28 #include "ldb_errors.h" 28 29 #include "../lib/util/util_ldb.h" … … 38 39 #include "libcli/auth/libcli_auth.h" 39 40 #include "librpc/gen_ndr/ndr_drsblobs.h" 41 #include "system/locale.h" 42 #include "lib/util/tsort.h" 43 #include "dsdb/common/util.h" 44 #include "lib/socket/socket.h" 45 #include "librpc/gen_ndr/irpc.h" 46 #include "libds/common/flag_mapping.h" 40 47 41 48 /* … … 106 113 } 107 114 108 return samdb_result_string(res[0], attr_name, NULL);115 return ldb_msg_find_attr_as_string(res[0], attr_name, NULL); 109 116 } 110 117 … … 192 199 { 193 200 va_list ap; 194 struct ldb_message **res; 195 const char * const attrs[] = { NULL }; 201 const char *attrs[] = { NULL }; 196 202 int ret; 197 203 198 204 va_start(ap, format); 199 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);205 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, NULL, attrs, format, ap); 200 206 va_end(ap); 201 207 … … 207 213 search the sam for a single integer attribute in exactly 1 record 208 214 */ 209 u int_t samdb_search_uint(struct ldb_context *sam_ldb,215 unsigned int samdb_search_uint(struct ldb_context *sam_ldb, 210 216 TALLOC_CTX *mem_ctx, 211 u int_t default_value,217 unsigned int default_value, 212 218 struct ldb_dn *basedn, 213 219 const char *attr_name, … … 229 235 } 230 236 231 return samdb_result_uint(res[0], attr_name, default_value);237 return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value); 232 238 } 233 239 … … 257 263 } 258 264 259 return samdb_result_int64(res[0], attr_name, default_value);265 return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value); 260 266 } 261 267 … … 303 309 304 310 for (i=0;i<count;i++) { 305 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);311 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL); 306 312 } 307 313 (*strs)[count] = NULL; 308 314 309 315 return count; 310 }311 312 /*313 pull a uint from a result set.314 */315 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)316 {317 return ldb_msg_find_attr_as_uint(msg, attr, default_value);318 }319 320 /*321 pull a (signed) int64 from a result set.322 */323 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)324 {325 return ldb_msg_find_attr_as_int64(msg, attr, default_value);326 }327 328 /*329 pull a string from a result set.330 */331 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,332 const char *default_value)333 {334 return ldb_msg_find_attr_as_string(msg, attr, default_value);335 316 } 336 317 … … 369 350 const char *attr) 370 351 { 352 bool ok; 371 353 const struct ldb_val *v; 372 354 struct dom_sid *sid; 373 enum ndr_err_code ndr_err;374 355 v = ldb_msg_find_ldb_val(msg, attr); 375 356 if (v == NULL) { … … 380 361 return NULL; 381 362 } 382 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid, 383 (ndr_pull_flags_fn_t)ndr_pull_dom_sid); 384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 363 ok = sid_blob_parse(*v, sid); 364 if (!ok) { 385 365 talloc_free(sid); 386 366 return NULL; … … 395 375 { 396 376 const struct ldb_val *v; 397 enum ndr_err_code ndr_err;398 377 struct GUID guid; 399 TALLOC_CTX *mem_ctx; 400 401 ZERO_STRUCT(guid); 378 NTSTATUS status; 402 379 403 380 v = ldb_msg_find_ldb_val(msg, attr); 404 if (!v) return guid; 405 406 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid"); 407 if (!mem_ctx) return guid; 408 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid, 409 (ndr_pull_flags_fn_t)ndr_pull_GUID); 410 talloc_free(mem_ctx); 411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 412 return guid; 381 if (!v) return GUID_zero(); 382 383 status = GUID_from_ndr_blob(v, &guid); 384 if (!NT_STATUS_IS_OK(status)) { 385 return GUID_zero(); 413 386 } 414 387 … … 432 405 pull a NTTIME in a result set. 433 406 */ 434 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value) 407 NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr, 408 NTTIME default_value) 435 409 { 436 410 return ldb_msg_find_attr_as_uint64(msg, attr, default_value); … … 443 417 * cause windows 2008 and newer version to fail for SMB requests 444 418 */ 445 NTTIME samdb_result_last_logoff( struct ldb_message *msg)419 NTTIME samdb_result_last_logoff(const struct ldb_message *msg) 446 420 { 447 421 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0); … … 465 439 * the rest of the code. 466 440 */ 467 NTTIME samdb_result_account_expires( struct ldb_message *msg)441 NTTIME samdb_result_account_expires(const struct ldb_message *msg) 468 442 { 469 443 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires", … … 475 449 return ret; 476 450 } 477 478 /*479 pull a uint64_t from a result set.480 */481 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)482 {483 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);484 }485 486 451 487 452 /* … … 495 460 const char *attr) 496 461 { 497 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);462 uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0); 498 463 int64_t minPwdAge; 499 464 … … 520 485 struct ldb_message *msg) 521 486 { 522 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0); 523 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0); 487 int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0); 488 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, 489 "userAccountControl", 490 0); 524 491 int64_t maxPwdAge; 525 492 … … 533 500 return 0; 534 501 } 535 536 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL); 502 if (attr_time == -1) { 503 return 0x7FFFFFFFFFFFFFFFULL; 504 } 505 506 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, 507 "maxPwdAge", NULL); 537 508 if (maxPwdAge == 0) { 538 509 return 0x7FFFFFFFFFFFFFFFULL; … … 559 530 560 531 /* 561 pull an array of samr_Password structu tres from a result set.562 */ 563 u int_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,532 pull an array of samr_Password structures from a result set. 533 */ 534 unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 564 535 const char *attr, struct samr_Password **hashes) 565 536 { 566 u int_t count = 0;537 unsigned int count, i; 567 538 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); 568 int i;569 539 570 540 *hashes = NULL; … … 589 559 } 590 560 591 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 561 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 592 562 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 593 563 { 594 564 struct samr_Password *lmPwdHash, *ntPwdHash; 595 565 if (nt_pwd) { 596 int num_nt;566 unsigned int num_nt; 597 567 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash); 598 568 if (num_nt == 0) { … … 608 578 * authentication, that we never use the LM hash, even 609 579 * if we store it */ 610 if (lp _lanman_auth(lp_ctx)) {611 int num_lm;580 if (lpcfg_lanman_auth(lp_ctx)) { 581 unsigned int num_lm; 612 582 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash); 613 583 if (num_lm == 0) { … … 631 601 { 632 602 struct samr_LogonHours hours; 633 const int units_per_week = 168;603 size_t units_per_week = 168; 634 604 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); 605 635 606 ZERO_STRUCT(hours); 636 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week); 607 608 if (val) { 609 units_per_week = val->length * 8; 610 } 611 612 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8); 637 613 if (!hours.bits) { 638 614 return hours; 639 615 } 640 616 hours.units_per_week = units_per_week; 641 memset(hours.bits, 0xFF, units_per_week );617 memset(hours.bits, 0xFF, units_per_week/8); 642 618 if (val) { 643 memcpy(hours.bits, val->data, MIN(val->length, units_per_week)); 644 } 619 memcpy(hours.bits, val->data, val->length); 620 } 621 645 622 return hours; 646 623 } … … 691 668 return s; 692 669 } 693 s.length = s.size = val->length /2;670 s.length = s.size = val->length; 694 671 memcpy(s.array, val->data, val->length); 695 672 … … 707 684 const char *name, const char *value) 708 685 { 709 int i;686 unsigned int i; 710 687 struct ldb_message_element *el = ldb_msg_find_element(msg, name); 711 688 … … 723 700 } 724 701 725 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)726 {727 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {728 return samdb_msg_add_string(ldb, msg, msg, name, set_value);729 }730 return LDB_SUCCESS;731 }732 733 702 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value) 734 703 { … … 740 709 } 741 710 742 return samdb_msg_add_string(ldb, msg, msg, name, set_value); 743 } 744 745 746 747 /* 748 add a string element to a message 749 */ 750 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 751 const char *attr_name, const char *str) 752 { 753 char *s = talloc_strdup(mem_ctx, str); 754 char *a = talloc_strdup(mem_ctx, attr_name); 755 if (s == NULL || a == NULL) { 756 return LDB_ERR_OPERATIONS_ERROR; 757 } 758 return ldb_msg_add_string(msg, a, s); 711 return ldb_msg_add_string(msg, name, set_value); 759 712 } 760 713 … … 769 722 770 723 ndr_err = ndr_push_struct_blob(&v, mem_ctx, 771 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),772 724 sid, 773 725 (ndr_push_flags_fn_t)ndr_push_dom_sid); 774 726 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 775 return -1;727 return ldb_operr(sam_ldb); 776 728 } 777 729 return ldb_msg_add_value(msg, attr_name, &v, NULL); … … 786 738 { 787 739 /* we use an empty replace rather than a delete, as it allows for 788 samdb_replace() to be used everywhere */740 dsdb_replace() to be used everywhere */ 789 741 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL); 790 742 } 791 743 792 744 /* 793 add a add attribute value to a message 794 */ 795 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 796 const char *attr_name, const char *value) 745 add an add attribute value to a message or enhance an existing attribute 746 which has the same name and the add flag set. 747 */ 748 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, 749 struct ldb_message *msg, const char *attr_name, 750 const char *value) 797 751 { 798 752 struct ldb_message_element *el; 799 char *a, *v; 800 int ret; 801 a = talloc_strdup(mem_ctx, attr_name); 802 if (a == NULL) 803 return -1; 753 struct ldb_val val, *vals; 754 char *v; 755 unsigned int i; 756 bool found = false; 757 int ret; 758 804 759 v = talloc_strdup(mem_ctx, value); 805 if (v == NULL) 806 return -1; 807 ret = ldb_msg_add_string(msg, a, v); 808 if (ret != 0) 809 return ret; 810 el = ldb_msg_find_element(msg, a); 811 if (el == NULL) 812 return -1; 813 el->flags = LDB_FLAG_MOD_ADD; 814 return 0; 815 } 816 817 /* 818 add a delete attribute value to a message 819 */ 820 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 821 const char *attr_name, const char *value) 760 if (v == NULL) { 761 return ldb_oom(sam_ldb); 762 } 763 764 val.data = (uint8_t *) v; 765 val.length = strlen(v); 766 767 if (val.length == 0) { 768 /* allow empty strings as non-existent attributes */ 769 return LDB_SUCCESS; 770 } 771 772 for (i = 0; i < msg->num_elements; i++) { 773 el = &msg->elements[i]; 774 if ((ldb_attr_cmp(el->name, attr_name) == 0) && 775 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) { 776 found = true; 777 break; 778 } 779 } 780 if (!found) { 781 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD, 782 &el); 783 if (ret != LDB_SUCCESS) { 784 return ret; 785 } 786 } 787 788 vals = talloc_realloc(msg->elements, el->values, struct ldb_val, 789 el->num_values + 1); 790 if (vals == NULL) { 791 return ldb_oom(sam_ldb); 792 } 793 el->values = vals; 794 el->values[el->num_values] = val; 795 ++(el->num_values); 796 797 return LDB_SUCCESS; 798 } 799 800 /* 801 add a delete attribute value to a message or enhance an existing attribute 802 which has the same name and the delete flag set. 803 */ 804 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, 805 struct ldb_message *msg, const char *attr_name, 806 const char *value) 822 807 { 823 808 struct ldb_message_element *el; 824 char *a, *v; 825 int ret; 826 a = talloc_strdup(mem_ctx, attr_name); 827 if (a == NULL) 828 return -1; 809 struct ldb_val val, *vals; 810 char *v; 811 unsigned int i; 812 bool found = false; 813 int ret; 814 829 815 v = talloc_strdup(mem_ctx, value); 830 if (v == NULL) 831 return -1; 832 ret = ldb_msg_add_string(msg, a, v); 833 if (ret != 0) 834 return ret; 835 el = ldb_msg_find_element(msg, a); 836 if (el == NULL) 837 return -1; 838 el->flags = LDB_FLAG_MOD_DELETE; 839 return 0; 816 if (v == NULL) { 817 return ldb_oom(sam_ldb); 818 } 819 820 val.data = (uint8_t *) v; 821 val.length = strlen(v); 822 823 if (val.length == 0) { 824 /* allow empty strings as non-existent attributes */ 825 return LDB_SUCCESS; 826 } 827 828 for (i = 0; i < msg->num_elements; i++) { 829 el = &msg->elements[i]; 830 if ((ldb_attr_cmp(el->name, attr_name) == 0) && 831 (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) { 832 found = true; 833 break; 834 } 835 } 836 if (!found) { 837 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE, 838 &el); 839 if (ret != LDB_SUCCESS) { 840 return ret; 841 } 842 } 843 844 vals = talloc_realloc(msg->elements, el->values, struct ldb_val, 845 el->num_values + 1); 846 if (vals == NULL) { 847 return ldb_oom(sam_ldb); 848 } 849 el->values = vals; 850 el->values[el->num_values] = val; 851 ++(el->num_values); 852 853 return LDB_SUCCESS; 840 854 } 841 855 … … 847 861 { 848 862 const char *s = talloc_asprintf(mem_ctx, "%d", v); 849 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); 850 } 851 852 /* 853 add a uint_t element to a message 854 */ 863 if (s == NULL) { 864 return ldb_oom(sam_ldb); 865 } 866 return ldb_msg_add_string(msg, attr_name, s); 867 } 868 869 /* 870 * Add an unsigned int element to a message 871 * 872 * The issue here is that we have not yet first cast to int32_t explicitly, 873 * before we cast to an signed int to printf() into the %d or cast to a 874 * int64_t before we then cast to a long long to printf into a %lld. 875 * 876 * There are *no* unsigned integers in Active Directory LDAP, even the RID 877 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities. 878 * (See the schema, and the syntax definitions in schema_syntax.c). 879 * 880 */ 855 881 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 856 const char *attr_name, uint_t v) 857 { 858 const char *s = talloc_asprintf(mem_ctx, "%u", v); 859 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); 882 const char *attr_name, unsigned int v) 883 { 884 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v); 860 885 } 861 886 … … 867 892 { 868 893 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v); 869 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); 870 } 871 872 /* 873 add a uint64_t element to a message 874 */ 894 if (s == NULL) { 895 return ldb_oom(sam_ldb); 896 } 897 return ldb_msg_add_string(msg, attr_name, s); 898 } 899 900 /* 901 * Add an unsigned int64_t (uint64_t) element to a message 902 * 903 * The issue here is that we have not yet first cast to int32_t explicitly, 904 * before we cast to an signed int to printf() into the %d or cast to a 905 * int64_t before we then cast to a long long to printf into a %lld. 906 * 907 * There are *no* unsigned integers in Active Directory LDAP, even the RID 908 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities. 909 * (See the schema, and the syntax definitions in schema_syntax.c). 910 * 911 */ 875 912 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 876 913 const char *attr_name, uint64_t v) 877 914 { 878 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v); 879 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); 915 return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v); 880 916 } 881 917 … … 884 920 */ 885 921 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 886 const char *attr_name, struct samr_Password *hash)922 const char *attr_name, const struct samr_Password *hash) 887 923 { 888 924 struct ldb_val val; 889 925 val.data = talloc_memdup(mem_ctx, hash->hash, 16); 890 926 if (!val.data) { 891 return -1;927 return ldb_oom(sam_ldb); 892 928 } 893 929 val.length = 16; … … 898 934 add a samr_Password array to a message 899 935 */ 900 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 901 const char *attr_name, struct samr_Password *hashes, uint_t count) 936 int samdb_msg_add_hashes(struct ldb_context *ldb, 937 TALLOC_CTX *mem_ctx, struct ldb_message *msg, 938 const char *attr_name, struct samr_Password *hashes, 939 unsigned int count) 902 940 { 903 941 struct ldb_val val; 904 int i;942 unsigned int i; 905 943 val.data = talloc_array_size(mem_ctx, 16, count); 906 944 val.length = count*16; 907 945 if (!val.data) { 908 return -1;946 return ldb_oom(ldb); 909 947 } 910 948 for (i=0;i<count;i++) { … … 942 980 { 943 981 struct ldb_val val; 944 val.length = parameters->length * 2;982 val.length = parameters->length; 945 983 val.data = (uint8_t *)parameters->array; 946 984 return ldb_msg_add_value(msg, attr_name, &val, NULL); 947 }948 /*949 add a general value element to a message950 */951 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,952 const char *attr_name, const struct ldb_val *val)953 {954 return ldb_msg_add_value(msg, attr_name, val, NULL);955 985 } 956 986 … … 982 1012 el->num_values = 0; 983 1013 } 984 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str); 985 } 986 987 /* 988 replace elements in a record 989 */ 990 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg) 991 { 992 int i; 993 994 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */ 995 for (i=0;i<msg->num_elements;i++) { 996 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; 997 } 998 999 /* modify the samdb record */ 1000 return ldb_modify(sam_ldb, msg); 1014 return ldb_msg_add_string(msg, attr_name, str); 1015 } 1016 1017 /* 1018 * sets a signed integer in a message 1019 */ 1020 int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, 1021 struct ldb_message *msg, const char *attr_name, int v) 1022 { 1023 struct ldb_message_element *el; 1024 1025 el = ldb_msg_find_element(msg, attr_name); 1026 if (el) { 1027 el->num_values = 0; 1028 } 1029 return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v); 1030 } 1031 1032 /* 1033 * Sets an unsigned int element in a message 1034 * 1035 * The issue here is that we have not yet first cast to int32_t explicitly, 1036 * before we cast to an signed int to printf() into the %d or cast to a 1037 * int64_t before we then cast to a long long to printf into a %lld. 1038 * 1039 * There are *no* unsigned integers in Active Directory LDAP, even the RID 1040 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities. 1041 * (See the schema, and the syntax definitions in schema_syntax.c). 1042 * 1043 */ 1044 int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, 1045 struct ldb_message *msg, const char *attr_name, 1046 unsigned int v) 1047 { 1048 struct ldb_message_element *el; 1049 1050 el = ldb_msg_find_element(msg, attr_name); 1051 if (el) { 1052 el->num_values = 0; 1053 } 1054 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v); 1055 } 1056 1057 /* 1058 * Handle ldb_request in transaction 1059 */ 1060 static int dsdb_autotransaction_request(struct ldb_context *sam_ldb, 1061 struct ldb_request *req) 1062 { 1063 int ret; 1064 1065 ret = ldb_transaction_start(sam_ldb); 1066 if (ret != LDB_SUCCESS) { 1067 return ret; 1068 } 1069 1070 ret = ldb_request(sam_ldb, req); 1071 if (ret == LDB_SUCCESS) { 1072 ret = ldb_wait(req->handle, LDB_WAIT_ALL); 1073 } 1074 1075 if (ret == LDB_SUCCESS) { 1076 return ldb_transaction_commit(sam_ldb); 1077 } 1078 ldb_transaction_cancel(sam_ldb); 1079 1080 return ret; 1001 1081 } 1002 1082 … … 1013 1093 } 1014 1094 1015 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 1016 { 1017 return ldb_get_default_basedn(sam_ctx); 1018 } 1019 1020 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 1021 { 1022 return ldb_get_config_basedn(sam_ctx); 1023 } 1024 1025 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 1026 { 1027 return ldb_get_schema_basedn(sam_ctx); 1028 } 1029 1030 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 1031 { 1032 return ldb_get_root_basedn(sam_ctx); 1095 struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 1096 { 1097 struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx); 1098 struct ldb_dn *aggregate_dn; 1099 if (!schema_dn) { 1100 return NULL; 1101 } 1102 1103 aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn); 1104 if (!aggregate_dn) { 1105 return NULL; 1106 } 1107 if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) { 1108 return NULL; 1109 } 1110 return aggregate_dn; 1033 1111 } 1034 1112 … … 1037 1115 struct ldb_dn *new_dn; 1038 1116 1039 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));1117 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx)); 1040 1118 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) { 1041 1119 talloc_free(new_dn); … … 1045 1123 } 1046 1124 1125 struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 1126 { 1127 struct ldb_dn *new_dn; 1128 1129 new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx)); 1130 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) { 1131 talloc_free(new_dn); 1132 return NULL; 1133 } 1134 return new_dn; 1135 } 1136 1047 1137 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 1048 1138 { 1049 1139 struct ldb_dn *new_dn; 1050 1140 1051 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));1141 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx)); 1052 1142 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) { 1053 1143 talloc_free(new_dn); … … 1108 1198 1109 1199 failed: 1110 DEBUG(1,("Failed to find domain_sid for open ldb\n"));1111 1200 talloc_free(tmp_ctx); 1112 1201 return NULL; 1202 } 1203 1204 /* 1205 get domain sid from cache 1206 */ 1207 const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb) 1208 { 1209 return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid"); 1113 1210 } 1114 1211 … … 1150 1247 } 1151 1248 1152 /* Obtain the short name of the flexible single master operator 1153 * (FSMO), such as the PDC Emulator */ 1154 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 1155 const char *attr) 1156 { 1157 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */ 1158 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr); 1159 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1); 1160 const char *name = ldb_dn_get_component_name(fsmo_dn, 1); 1161 1162 if (!name || (ldb_attr_cmp(name, "cn") != 0)) { 1163 /* Ensure this matches the format. This gives us a 1164 * bit more confidence that a 'cn' value will be a 1165 * ascii string */ 1166 return NULL; 1167 } 1168 if (val) { 1169 return (char *)val->data; 1170 } 1171 return NULL; 1249 bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in) 1250 { 1251 TALLOC_CTX *tmp_ctx; 1252 struct ldb_dn *ntds_settings_dn_new; 1253 struct ldb_dn *ntds_settings_dn_old; 1254 1255 /* see if we have a cached copy */ 1256 ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb, 1257 "cache.ntds_settings_dn"), struct ldb_dn); 1258 1259 tmp_ctx = talloc_new(ldb); 1260 if (tmp_ctx == NULL) { 1261 goto failed; 1262 } 1263 1264 ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in); 1265 if (!ntds_settings_dn_new) { 1266 goto failed; 1267 } 1268 1269 /* cache the domain_sid in the ldb */ 1270 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) { 1271 goto failed; 1272 } 1273 1274 talloc_steal(ldb, ntds_settings_dn_new); 1275 talloc_free(tmp_ctx); 1276 talloc_free(ntds_settings_dn_old); 1277 1278 return true; 1279 1280 failed: 1281 DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n")); 1282 talloc_free(tmp_ctx); 1283 return false; 1172 1284 } 1173 1285 … … 1184 1296 1185 1297 /* see if we have a cached copy */ 1186 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache. settings_dn");1298 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn"); 1187 1299 if (settings_dn) { 1188 1300 return settings_dn; … … 1208 1320 1209 1321 /* cache the domain_sid in the ldb */ 1210 if (ldb_set_opaque(ldb, "cache. settings_dn", settings_dn) != LDB_SUCCESS) {1322 if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", settings_dn) != LDB_SUCCESS) { 1211 1323 goto failed; 1212 1324 } … … 1422 1534 { 1423 1535 struct ldb_dn *server_dn; 1536 struct ldb_dn *servers_dn; 1424 1537 struct ldb_dn *server_site_dn; 1425 1538 1539 /* TODO: there must be a saner way to do this!! */ 1426 1540 server_dn = samdb_server_dn(ldb, mem_ctx); 1427 1541 if (!server_dn) return NULL; 1428 1542 1429 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn); 1430 1543 servers_dn = ldb_dn_get_parent(mem_ctx, server_dn); 1431 1544 talloc_free(server_dn); 1545 if (!servers_dn) return NULL; 1546 1547 server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn); 1548 talloc_free(servers_dn); 1549 1432 1550 return server_site_dn; 1433 1551 } 1434 1552 1435 1553 /* 1436 * This works out if we are running on a supported forest/domain function 1437 * level. Basically this means that we don't support mixed/interim (NT 4 DC 1438 * support) levels. 1439 * If errmsg isn't NULL we write in an adequate error message for printing out 1440 * to the screen. 1441 */ 1442 bool samdb_is_capable_dc(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 1443 char **errmsg) 1444 { 1445 int32_t level_forest, level_domain, level_domain_mixed; 1446 bool ret = true; 1447 1448 level_forest = (int32_t) samdb_search_int64(ldb, mem_ctx, -1, 1449 samdb_partitions_dn(ldb, mem_ctx), "msDS-Behavior-Version", 1450 NULL); 1451 level_domain = (int32_t) samdb_search_int64(ldb, mem_ctx, -1, 1452 samdb_base_dn(ldb), "msDS-Behavior-Version", NULL); 1453 level_domain_mixed = (int32_t) samdb_search_int64(ldb, mem_ctx, -1, 1454 samdb_base_dn(ldb), "nTMixedDomain", NULL); 1455 1456 if (errmsg != NULL) 1457 *errmsg = talloc_strdup(mem_ctx, ""); 1458 1459 if (level_forest == -1 || level_domain == -1 || level_domain_mixed == -1) { 1460 ret = false; 1461 if (errmsg != NULL) 1462 *errmsg = talloc_strdup_append(*errmsg, 1463 "\nATTENTION: Invalid values for forest and/or domain function level!" 1464 ); 1465 } 1466 1467 if (level_forest == DS_DOMAIN_FUNCTION_2003_MIXED) { 1468 ret = false; 1469 if (errmsg != NULL) 1470 *errmsg = talloc_strdup_append(*errmsg, 1471 "\nATTENTION: You run SAMBA 4 on the 2003 with mixed domains (NT4 DC support) forest level. This isn't supported!" 1472 ); 1473 } 1474 if ((level_domain == DS_DOMAIN_FUNCTION_2000 && level_domain_mixed != 0) 1475 || level_domain == DS_DOMAIN_FUNCTION_2003_MIXED) { 1476 ret = false; 1477 if (errmsg != NULL) 1478 *errmsg = talloc_strdup_append(*errmsg, 1479 "\nATTENTION: You run SAMBA 4 on a mixed/interim (NT4 DC support) domain level. This isn't supported!" 1480 ); 1481 } 1482 1483 if ((!ret) && (errmsg != NULL)) { 1484 *errmsg = talloc_strdup_append(*errmsg, 1485 "\nPlease raise the domain and/or forest level to an adequate value. Use for this the 'domainlevel' tool, the MS AD MMC tools or manipulate the needed attributes directly." 1486 ); 1487 } 1488 1554 find the site name from a computers DN record 1555 */ 1556 int samdb_find_site_for_computer(struct ldb_context *ldb, 1557 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn, 1558 const char **site_name) 1559 { 1560 int ret; 1561 struct ldb_dn *dn; 1562 const struct ldb_val *rdn_val; 1563 1564 *site_name = NULL; 1565 1566 ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn); 1567 if (ret != LDB_SUCCESS) { 1568 return ret; 1569 } 1570 1571 if (!ldb_dn_remove_child_components(dn, 2)) { 1572 talloc_free(dn); 1573 return LDB_ERR_INVALID_DN_SYNTAX; 1574 } 1575 1576 rdn_val = ldb_dn_get_rdn_val(dn); 1577 if (rdn_val == NULL) { 1578 return LDB_ERR_OPERATIONS_ERROR; 1579 } 1580 1581 (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length); 1582 talloc_free(dn); 1583 if (!*site_name) { 1584 return LDB_ERR_OPERATIONS_ERROR; 1585 } 1586 return LDB_SUCCESS; 1587 } 1588 1589 /* 1590 find the NTDS GUID from a computers DN record 1591 */ 1592 int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn, 1593 struct GUID *ntds_guid) 1594 { 1595 int ret; 1596 struct ldb_dn *dn; 1597 1598 *ntds_guid = GUID_zero(); 1599 1600 ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn); 1601 if (ret != LDB_SUCCESS) { 1602 return ret; 1603 } 1604 1605 if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) { 1606 talloc_free(dn); 1607 return LDB_ERR_OPERATIONS_ERROR; 1608 } 1609 1610 ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid); 1611 talloc_free(dn); 1489 1612 return ret; 1613 } 1614 1615 /* 1616 find a 'reference' DN that points at another object 1617 (eg. serverReference, rIDManagerReference etc) 1618 */ 1619 int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base, 1620 const char *attribute, struct ldb_dn **dn) 1621 { 1622 const char *attrs[2]; 1623 struct ldb_result *res; 1624 int ret; 1625 1626 attrs[0] = attribute; 1627 attrs[1] = NULL; 1628 1629 ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL); 1630 if (ret != LDB_SUCCESS) { 1631 return ret; 1632 } 1633 1634 *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute); 1635 if (!*dn) { 1636 if (!ldb_msg_find_element(res->msgs[0], attribute)) { 1637 ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute, 1638 ldb_dn_get_linearized(base)); 1639 } else { 1640 ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute, 1641 ldb_dn_get_linearized(base)); 1642 } 1643 talloc_free(res); 1644 return LDB_ERR_NO_SUCH_ATTRIBUTE; 1645 } 1646 1647 talloc_free(res); 1648 return LDB_SUCCESS; 1649 } 1650 1651 /* 1652 find our machine account via the serverReference attribute in the 1653 server DN 1654 */ 1655 int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn) 1656 { 1657 struct ldb_dn *server_dn; 1658 int ret; 1659 1660 server_dn = samdb_server_dn(ldb, mem_ctx); 1661 if (server_dn == NULL) { 1662 return LDB_ERR_NO_SUCH_OBJECT; 1663 } 1664 1665 ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn); 1666 talloc_free(server_dn); 1667 1668 return ret; 1669 } 1670 1671 /* 1672 find the RID Manager$ DN via the rIDManagerReference attribute in the 1673 base DN 1674 */ 1675 int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn) 1676 { 1677 return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb), 1678 "rIDManagerReference", dn); 1679 } 1680 1681 /* 1682 find the RID Set DN via the rIDSetReferences attribute in our 1683 machine account DN 1684 */ 1685 int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn) 1686 { 1687 struct ldb_dn *server_ref_dn; 1688 int ret; 1689 1690 ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn); 1691 if (ret != LDB_SUCCESS) { 1692 return ret; 1693 } 1694 ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn); 1695 talloc_free(server_ref_dn); 1696 return ret; 1697 } 1698 1699 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 1700 { 1701 const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb, 1702 mem_ctx)); 1703 1704 if (val == NULL) { 1705 return NULL; 1706 } 1707 1708 return (const char *) val->data; 1709 } 1710 1711 /* 1712 * Finds the client site by using the client's IP address. 1713 * The "subnet_name" returns the name of the subnet if parameter != NULL 1714 */ 1715 const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 1716 const char *ip_address, char **subnet_name) 1717 { 1718 const char *attrs[] = { "cn", "siteObject", NULL }; 1719 struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn; 1720 struct ldb_result *res; 1721 const struct ldb_val *val; 1722 const char *site_name = NULL, *l_subnet_name = NULL; 1723 const char *allow_list[2] = { NULL, NULL }; 1724 unsigned int i, count; 1725 int cnt, ret; 1726 1727 /* 1728 * if we don't have a client ip e.g. ncalrpc 1729 * the server site is the client site 1730 */ 1731 if (ip_address == NULL) { 1732 return samdb_server_site_name(ldb, mem_ctx); 1733 } 1734 1735 sites_container_dn = samdb_sites_dn(ldb, mem_ctx); 1736 if (sites_container_dn == NULL) { 1737 return NULL; 1738 } 1739 1740 subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn); 1741 if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) { 1742 talloc_free(sites_container_dn); 1743 talloc_free(subnets_dn); 1744 return NULL; 1745 } 1746 1747 ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL, 1748 attrs, NULL); 1749 if (ret == LDB_ERR_NO_SUCH_OBJECT) { 1750 count = 0; 1751 } else if (ret != LDB_SUCCESS) { 1752 talloc_free(sites_container_dn); 1753 talloc_free(subnets_dn); 1754 return NULL; 1755 } else { 1756 count = res->count; 1757 } 1758 1759 for (i = 0; i < count; i++) { 1760 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn", 1761 NULL); 1762 1763 allow_list[0] = l_subnet_name; 1764 1765 if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) { 1766 sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, 1767 res->msgs[i], 1768 "siteObject"); 1769 if (sites_dn == NULL) { 1770 /* No reference, maybe another subnet matches */ 1771 continue; 1772 } 1773 1774 /* "val" cannot be NULL here since "sites_dn" != NULL */ 1775 val = ldb_dn_get_rdn_val(sites_dn); 1776 site_name = talloc_strdup(mem_ctx, 1777 (const char *) val->data); 1778 1779 talloc_free(sites_dn); 1780 1781 break; 1782 } 1783 } 1784 1785 if (site_name == NULL) { 1786 /* This is the Windows Server fallback rule: when no subnet 1787 * exists and we have only one site available then use it (it 1788 * is for sure the same as our server site). If more sites do 1789 * exist then we don't know which one to use and set the site 1790 * name to "". */ 1791 cnt = samdb_search_count(ldb, mem_ctx, sites_container_dn, 1792 "(objectClass=site)"); 1793 if (cnt == 1) { 1794 site_name = samdb_server_site_name(ldb, mem_ctx); 1795 } else { 1796 site_name = talloc_strdup(mem_ctx, ""); 1797 } 1798 l_subnet_name = NULL; 1799 } 1800 1801 if (subnet_name != NULL) { 1802 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name); 1803 } 1804 1805 talloc_free(sites_container_dn); 1806 talloc_free(subnets_dn); 1807 talloc_free(res); 1808 1809 return site_name; 1490 1810 } 1491 1811 … … 1509 1829 1510 1830 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL); 1511 if (ret ) {1831 if (ret != LDB_SUCCESS) { 1512 1832 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 1513 1833 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), … … 1543 1863 { 1544 1864 const char *attrs[] = { "options", NULL }; 1545 int ret, options; 1865 uint32_t options; 1866 int ret; 1546 1867 struct ldb_result *res; 1547 1868 TALLOC_CTX *tmp_ctx; … … 1555 1876 /* Query cn=ntds settings,.... */ 1556 1877 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); 1557 if (ret ) {1878 if (ret != LDB_SUCCESS) { 1558 1879 talloc_free(tmp_ctx); 1559 1880 return false; … … 1564 1885 } 1565 1886 1566 options = ldb_msg_find_attr_as_ int(res->msgs[0], "options", 0);1887 options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0); 1567 1888 talloc_free(tmp_ctx); 1568 1889 1569 1890 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */ 1570 if (options & 0x000000001) {1891 if (options & DS_NTDSDSA_OPT_IS_GC) { 1571 1892 return true; 1572 1893 } … … 1581 1902 struct ldb_dn *sdn = dn; 1582 1903 struct ldb_result *res = NULL; 1583 int ret = 0;1904 int ret = LDB_SUCCESS; 1584 1905 const char *attrs[] = { NULL }; 1585 1906 1586 1907 local_ctx = talloc_new(mem_ctx); 1587 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;1908 if (local_ctx == NULL) return ldb_oom(ldb); 1588 1909 1589 1910 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) { 1590 1911 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs, 1591 "(|( |(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");1912 "(|(objectClass=domain)(objectClass=builtinDomain))"); 1592 1913 if (ret == LDB_SUCCESS) { 1593 1914 if (res->count == 1) { … … 1622 1943 1623 1944 /* 1624 set the user password using plaintext, obeying any user or domain 1625 password restrictions 1626 1627 note that this function doesn't actually store the result in the 1628 database, it just fills in the "mod" structure with ldb modify 1629 elements to setup the correct change when samdb_replace() is 1630 called. This allows the caller to combine the change with other 1631 changes (as is needed by some of the set user info levels) 1632 1633 The caller should probably have a transaction wrapping this 1634 */ 1635 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, 1636 struct ldb_dn *user_dn, 1637 struct ldb_dn *domain_dn, 1638 struct ldb_message *mod, 1945 * Performs checks on a user password (plaintext UNIX format - attribute 1946 * "password"). The remaining parameters have to be extracted from the domain 1947 * object in the AD. 1948 * 1949 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl") 1950 */ 1951 enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password, 1952 const uint32_t pwdProperties, 1953 const uint32_t minPwdLength) 1954 { 1955 /* checks if the "minPwdLength" property is satisfied */ 1956 if (minPwdLength > password->length) 1957 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT; 1958 1959 /* checks the password complexity */ 1960 if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0) 1961 && (password->data != NULL) 1962 && (!check_password_quality((const char *) password->data))) 1963 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; 1964 1965 return SAMR_VALIDATION_STATUS_SUCCESS; 1966 } 1967 1968 /* 1969 * Callback for "samdb_set_password" password change 1970 */ 1971 int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares) 1972 { 1973 int ret; 1974 1975 if (!ares) { 1976 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); 1977 } 1978 1979 if (ares->error != LDB_SUCCESS) { 1980 ret = ares->error; 1981 req->context = talloc_steal(req, 1982 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID)); 1983 talloc_free(ares); 1984 return ldb_request_done(req, ret); 1985 } 1986 1987 if (ares->type != LDB_REPLY_DONE) { 1988 talloc_free(ares); 1989 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); 1990 } 1991 1992 req->context = talloc_steal(req, 1993 ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID)); 1994 talloc_free(ares); 1995 return ldb_request_done(req, LDB_SUCCESS); 1996 } 1997 1998 /* 1999 * Sets the user password using plaintext UTF16 (attribute "new_password") or 2000 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass 2001 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a 2002 * user change or not. The "rejectReason" gives some more information if the 2003 * change failed. 2004 * 2005 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL, 2006 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION 2007 */ 2008 NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 2009 struct ldb_dn *user_dn, struct ldb_dn *domain_dn, 1639 2010 const DATA_BLOB *new_password, 1640 struct samr_Password *param_lmNewHash, 1641 struct samr_Password *param_ntNewHash, 1642 bool user_change, 1643 enum samr_RejectReason *reject_reason, 2011 const struct samr_Password *lmNewHash, 2012 const struct samr_Password *ntNewHash, 2013 const struct samr_Password *lmOldHash, 2014 const struct samr_Password *ntOldHash, 2015 enum samPwdChangeReason *reject_reason, 1644 2016 struct samr_DomInfo1 **_dominfo) 1645 2017 { 1646 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 1647 "ntPwdHistory", 1648 "dBCSPwd", "unicodePwd", 1649 "objectSid", 1650 "pwdLastSet", NULL }; 1651 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 1652 "maxPwdAge", "minPwdAge", 1653 "minPwdLength", NULL }; 1654 NTTIME pwdLastSet; 1655 int64_t minPwdAge; 1656 uint_t minPwdLength, pwdProperties, pwdHistoryLength; 1657 uint_t userAccountControl; 1658 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, 1659 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash; 1660 struct samr_Password local_lmNewHash, local_ntNewHash; 1661 int sambaLMPwdHistory_len, sambaNTPwdHistory_len; 1662 struct dom_sid *domain_sid; 1663 struct ldb_message **res; 1664 bool restrictions; 1665 int count; 1666 time_t now = time(NULL); 1667 NTTIME now_nt; 1668 int i; 1669 1670 /* we need to know the time to compute password age */ 1671 unix_to_nt_time(&now_nt, now); 1672 1673 /* pull all the user parameters */ 1674 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs); 1675 if (count != 1) { 1676 return NT_STATUS_INTERNAL_DB_CORRUPTION; 1677 } 1678 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0); 1679 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], 1680 "lmPwdHistory", &sambaLMPwdHistory); 1681 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], 1682 "ntPwdHistory", &sambaNTPwdHistory); 1683 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd"); 1684 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd"); 1685 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0); 1686 1687 /* Copy parameters */ 1688 lmNewHash = param_lmNewHash; 1689 ntNewHash = param_ntNewHash; 1690 1691 /* Only non-trust accounts have restrictions (possibly this 1692 * test is the wrong way around, but I like to be restrictive 1693 * if possible */ 1694 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT 1695 |UF_WORKSTATION_TRUST_ACCOUNT 1696 |UF_SERVER_TRUST_ACCOUNT)); 1697 1698 if (domain_dn) { 1699 /* pull the domain parameters */ 1700 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs); 1701 if (count != 1) { 1702 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 1703 ldb_dn_get_linearized(domain_dn), 1704 ldb_dn_get_linearized(user_dn))); 1705 return NT_STATUS_NO_SUCH_DOMAIN; 2018 struct ldb_message *msg; 2019 struct ldb_message_element *el; 2020 struct ldb_request *req; 2021 struct dsdb_control_password_change_status *pwd_stat = NULL; 2022 int ret; 2023 NTSTATUS status = NT_STATUS_OK; 2024 2025 #define CHECK_RET(x) \ 2026 if (x != LDB_SUCCESS) { \ 2027 talloc_free(msg); \ 2028 return NT_STATUS_NO_MEMORY; \ 2029 } 2030 2031 msg = ldb_msg_new(mem_ctx); 2032 if (msg == NULL) { 2033 return NT_STATUS_NO_MEMORY; 2034 } 2035 msg->dn = user_dn; 2036 if ((new_password != NULL) 2037 && ((lmNewHash == NULL) && (ntNewHash == NULL))) { 2038 /* we have the password as plaintext UTF16 */ 2039 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword", 2040 new_password, NULL)); 2041 el = ldb_msg_find_element(msg, "clearTextPassword"); 2042 el->flags = LDB_FLAG_MOD_REPLACE; 2043 } else if ((new_password == NULL) 2044 && ((lmNewHash != NULL) || (ntNewHash != NULL))) { 2045 /* we have a password as LM and/or NT hash */ 2046 if (lmNewHash != NULL) { 2047 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg, 2048 "dBCSPwd", lmNewHash)); 2049 el = ldb_msg_find_element(msg, "dBCSPwd"); 2050 el->flags = LDB_FLAG_MOD_REPLACE; 2051 } 2052 if (ntNewHash != NULL) { 2053 CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg, 2054 "unicodePwd", ntNewHash)); 2055 el = ldb_msg_find_element(msg, "unicodePwd"); 2056 el->flags = LDB_FLAG_MOD_REPLACE; 1706 2057 } 1707 2058 } else { 1708 /* work out the domain sid, and pull the domain from there */ 1709 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid"); 1710 if (domain_sid == NULL) { 1711 return NT_STATUS_INTERNAL_DB_CORRUPTION; 1712 } 1713 1714 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 1715 "(objectSid=%s)", 1716 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); 1717 if (count != 1) { 1718 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 1719 dom_sid_string(mem_ctx, domain_sid), 1720 ldb_dn_get_linearized(user_dn))); 1721 return NT_STATUS_NO_SUCH_DOMAIN; 1722 } 1723 } 1724 1725 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0); 1726 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0); 1727 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0); 1728 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0); 1729 1730 if (userAccountControl & UF_PASSWD_NOTREQD) { 1731 /* see [MS-ADTS] 2.2.15 */ 1732 minPwdLength = 0; 1733 } 1734 1735 if (_dominfo) { 2059 /* the password wasn't specified correctly */ 2060 talloc_free(msg); 2061 return NT_STATUS_INVALID_PARAMETER; 2062 } 2063 2064 /* build modify request */ 2065 ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL, 2066 samdb_set_password_callback, NULL); 2067 if (ret != LDB_SUCCESS) { 2068 talloc_free(msg); 2069 return NT_STATUS_NO_MEMORY; 2070 } 2071 2072 /* A password change operation */ 2073 if ((ntOldHash != NULL) || (lmOldHash != NULL)) { 2074 struct dsdb_control_password_change *change; 2075 2076 change = talloc(req, struct dsdb_control_password_change); 2077 if (change == NULL) { 2078 talloc_free(req); 2079 talloc_free(msg); 2080 return NT_STATUS_NO_MEMORY; 2081 } 2082 2083 change->old_nt_pwd_hash = ntOldHash; 2084 change->old_lm_pwd_hash = lmOldHash; 2085 2086 ret = ldb_request_add_control(req, 2087 DSDB_CONTROL_PASSWORD_CHANGE_OID, 2088 true, change); 2089 if (ret != LDB_SUCCESS) { 2090 talloc_free(req); 2091 talloc_free(msg); 2092 return NT_STATUS_NO_MEMORY; 2093 } 2094 } 2095 ret = ldb_request_add_control(req, 2096 DSDB_CONTROL_PASSWORD_HASH_VALUES_OID, 2097 true, NULL); 2098 if (ret != LDB_SUCCESS) { 2099 talloc_free(req); 2100 talloc_free(msg); 2101 return NT_STATUS_NO_MEMORY; 2102 } 2103 ret = ldb_request_add_control(req, 2104 DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID, 2105 true, NULL); 2106 if (ret != LDB_SUCCESS) { 2107 talloc_free(req); 2108 talloc_free(msg); 2109 return NT_STATUS_NO_MEMORY; 2110 } 2111 2112 ret = dsdb_autotransaction_request(ldb, req); 2113 2114 if (req->context != NULL) { 2115 pwd_stat = talloc_steal(mem_ctx, 2116 ((struct ldb_control *)req->context)->data); 2117 } 2118 2119 talloc_free(req); 2120 talloc_free(msg); 2121 2122 /* Sets the domain info (if requested) */ 2123 if (_dominfo != NULL) { 1736 2124 struct samr_DomInfo1 *dominfo; 1737 /* on failure we need to fill in the reject reasons */ 1738 dominfo = talloc (mem_ctx, struct samr_DomInfo1);2125 2126 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1); 1739 2127 if (dominfo == NULL) { 1740 2128 return NT_STATUS_NO_MEMORY; 1741 2129 } 1742 dominfo->min_password_length = minPwdLength; 1743 dominfo->password_properties = pwdProperties; 1744 dominfo->password_history_length = pwdHistoryLength; 1745 dominfo->max_password_age = minPwdAge; 1746 dominfo->min_password_age = minPwdAge; 2130 2131 if (pwd_stat != NULL) { 2132 dominfo->min_password_length = pwd_stat->domain_data.minPwdLength; 2133 dominfo->password_properties = pwd_stat->domain_data.pwdProperties; 2134 dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength; 2135 dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge; 2136 dominfo->min_password_age = pwd_stat->domain_data.minPwdAge; 2137 } 2138 1747 2139 *_dominfo = dominfo; 1748 2140 } 1749 2141 1750 if (restrictions && new_password) { 1751 char *new_pass; 1752 1753 /* check the various password restrictions */ 1754 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) { 1755 if (reject_reason) { 1756 *reject_reason = SAMR_REJECT_TOO_SHORT; 2142 if (reject_reason != NULL) { 2143 if (pwd_stat != NULL) { 2144 *reject_reason = pwd_stat->reject_reason; 2145 } else { 2146 *reject_reason = SAM_PWD_CHANGE_NO_ERROR; 2147 } 2148 } 2149 2150 if (pwd_stat != NULL) { 2151 talloc_free(pwd_stat); 2152 } 2153 2154 if (ret == LDB_ERR_CONSTRAINT_VIOLATION) { 2155 const char *errmsg = ldb_errstring(ldb); 2156 char *endptr = NULL; 2157 WERROR werr = WERR_GENERAL_FAILURE; 2158 status = NT_STATUS_UNSUCCESSFUL; 2159 if (errmsg != NULL) { 2160 werr = W_ERROR(strtol(errmsg, &endptr, 16)); 2161 } 2162 if (endptr != errmsg) { 2163 if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) { 2164 status = NT_STATUS_WRONG_PASSWORD; 1757 2165 } 1758 return NT_STATUS_PASSWORD_RESTRICTION; 1759 } 1760 1761 /* Create the NT hash */ 1762 mdfour(local_ntNewHash.hash, new_password->data, new_password->length); 1763 1764 ntNewHash = &local_ntNewHash; 1765 1766 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */ 1767 if (convert_string_talloc_convenience(mem_ctx, 1768 lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")), 1769 CH_UTF16, CH_UNIX, 1770 new_password->data, new_password->length, 1771 (void **)&new_pass, NULL, false)) { 1772 1773 /* possibly check password complexity */ 1774 if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) && 1775 !check_password_quality(new_pass)) { 1776 if (reject_reason) { 1777 *reject_reason = SAMR_REJECT_COMPLEXITY; 1778 } 1779 return NT_STATUS_PASSWORD_RESTRICTION; 2166 if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) { 2167 status = NT_STATUS_PASSWORD_RESTRICTION; 1780 2168 } 1781 1782 /* compute the new lm hashes (for checking history - case insenitivly!) */ 1783 if (E_deshash(new_pass, local_lmNewHash.hash)) { 1784 lmNewHash = &local_lmNewHash; 1785 } 1786 } 1787 } 1788 1789 if (restrictions && user_change) { 1790 /* are all password changes disallowed? */ 1791 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { 1792 if (reject_reason) { 1793 *reject_reason = SAMR_REJECT_OTHER; 1794 } 1795 return NT_STATUS_PASSWORD_RESTRICTION; 1796 } 1797 1798 /* can this user change password? */ 1799 if (userAccountControl & UF_PASSWD_CANT_CHANGE) { 1800 if (reject_reason) { 1801 *reject_reason = SAMR_REJECT_OTHER; 1802 } 1803 return NT_STATUS_PASSWORD_RESTRICTION; 1804 } 1805 1806 /* yes, this is a minus. The ages are in negative 100nsec units! */ 1807 if (pwdLastSet - minPwdAge > now_nt) { 1808 if (reject_reason) { 1809 *reject_reason = SAMR_REJECT_OTHER; 1810 } 1811 return NT_STATUS_PASSWORD_RESTRICTION; 1812 } 1813 1814 /* check the immediately past password */ 1815 if (pwdHistoryLength > 0) { 1816 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) { 1817 if (reject_reason) { 1818 *reject_reason = SAMR_REJECT_IN_HISTORY; 1819 } 1820 return NT_STATUS_PASSWORD_RESTRICTION; 1821 } 1822 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) { 1823 if (reject_reason) { 1824 *reject_reason = SAMR_REJECT_IN_HISTORY; 1825 } 1826 return NT_STATUS_PASSWORD_RESTRICTION; 1827 } 1828 } 1829 1830 /* check the password history */ 1831 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength); 1832 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength); 1833 1834 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) { 1835 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) { 1836 if (reject_reason) { 1837 *reject_reason = SAMR_REJECT_IN_HISTORY; 1838 } 1839 return NT_STATUS_PASSWORD_RESTRICTION; 1840 } 1841 } 1842 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) { 1843 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) { 1844 if (reject_reason) { 1845 *reject_reason = SAMR_REJECT_IN_HISTORY; 1846 } 1847 return NT_STATUS_PASSWORD_RESTRICTION; 1848 } 1849 } 1850 } 1851 1852 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0) 1853 1854 /* the password is acceptable. Start forming the new fields */ 1855 if (new_password) { 1856 /* if we know the cleartext UTF16 password, then set it. 1857 * Modules in ldb will set all the appropriate 1858 * hashes */ 1859 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL)); 1860 } else { 1861 /* We don't have the cleartext, so delete the old one 1862 * and set what we have of the hashes */ 1863 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword")); 1864 1865 if (lmNewHash) { 1866 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash)); 1867 } else { 1868 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd")); 1869 } 1870 1871 if (ntNewHash) { 1872 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash)); 1873 } else { 1874 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd")); 1875 } 1876 } 1877 1878 return NT_STATUS_OK; 1879 } 1880 1881 1882 /* 1883 set the user password using plaintext, obeying any user or domain 1884 password restrictions 1885 1886 This wrapper function takes a SID as input, rather than a user DN, 1887 and actually performs the password change 1888 1889 */ 1890 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, 2169 } 2170 } else if (ret == LDB_ERR_NO_SUCH_OBJECT) { 2171 /* don't let the caller know if an account doesn't exist */ 2172 status = NT_STATUS_WRONG_PASSWORD; 2173 } else if (ret != LDB_SUCCESS) { 2174 status = NT_STATUS_UNSUCCESSFUL; 2175 } 2176 2177 return status; 2178 } 2179 2180 /* 2181 * Sets the user password using plaintext UTF16 (attribute "new_password") or 2182 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass 2183 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a 2184 * user change or not. The "rejectReason" gives some more information if the 2185 * change failed. 2186 * 2187 * This wrapper function for "samdb_set_password" takes a SID as input rather 2188 * than a user DN. 2189 * 2190 * This call encapsulates a new LDB transaction for changing the password; 2191 * therefore the user hasn't to start a new one. 2192 * 2193 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION, 2194 * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL, 2195 * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION, 2196 * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER 2197 */ 2198 NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 1891 2199 const struct dom_sid *user_sid, 1892 const DATA_BLOB *new_pass, 1893 struct samr_Password *lmNewHash, 1894 struct samr_Password *ntNewHash, 1895 bool user_change, 1896 enum samr_RejectReason *reject_reason, 2200 const DATA_BLOB *new_password, 2201 const struct samr_Password *lmNewHash, 2202 const struct samr_Password *ntNewHash, 2203 const struct samr_Password *lmOldHash, 2204 const struct samr_Password *ntOldHash, 2205 enum samPwdChangeReason *reject_reason, 1897 2206 struct samr_DomInfo1 **_dominfo) 1898 2207 { 1899 2208 NTSTATUS nt_status; 1900 2209 struct ldb_dn *user_dn; 1901 struct ldb_message *msg; 1902 int ret; 1903 1904 ret = ldb_transaction_start(ctx); 1905 if (ret) { 1906 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx))); 2210 int ret; 2211 2212 ret = ldb_transaction_start(ldb); 2213 if (ret != LDB_SUCCESS) { 2214 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb))); 1907 2215 return NT_STATUS_TRANSACTION_ABORTED; 1908 2216 } 1909 2217 1910 user_dn = samdb_search_dn( ctx, mem_ctx, NULL,2218 user_dn = samdb_search_dn(ldb, mem_ctx, NULL, 1911 2219 "(&(objectSid=%s)(objectClass=user))", 1912 2220 ldap_encode_ndr_dom_sid(mem_ctx, user_sid)); 1913 2221 if (!user_dn) { 1914 ldb_transaction_cancel( ctx);2222 ldb_transaction_cancel(ldb); 1915 2223 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n", 1916 2224 dom_sid_string(mem_ctx, user_sid))); … … 1918 2226 } 1919 2227 1920 msg = ldb_msg_new(mem_ctx); 1921 if (msg == NULL) { 1922 ldb_transaction_cancel(ctx); 1923 return NT_STATUS_NO_MEMORY; 1924 } 1925 1926 msg->dn = ldb_dn_copy(msg, user_dn); 1927 if (!msg->dn) { 1928 ldb_transaction_cancel(ctx); 1929 return NT_STATUS_NO_MEMORY; 1930 } 1931 1932 nt_status = samdb_set_password(ctx, mem_ctx, 2228 nt_status = samdb_set_password(ldb, mem_ctx, 1933 2229 user_dn, NULL, 1934 msg, new_pass,2230 new_password, 1935 2231 lmNewHash, ntNewHash, 1936 user_change, /* This is a password set, not change */2232 lmOldHash, ntOldHash, 1937 2233 reject_reason, _dominfo); 1938 2234 if (!NT_STATUS_IS_OK(nt_status)) { 1939 ldb_transaction_cancel(ctx); 2235 ldb_transaction_cancel(ldb); 2236 talloc_free(user_dn); 1940 2237 return nt_status; 1941 2238 } 1942 2239 1943 /* modify the samdb record */ 1944 ret = samdb_replace(ctx, mem_ctx, msg); 1945 if (ret != 0) { 1946 ldb_transaction_cancel(ctx); 1947 return NT_STATUS_ACCESS_DENIED; 1948 } 1949 1950 ret = ldb_transaction_commit(ctx); 1951 if (ret != 0) { 2240 ret = ldb_transaction_commit(ldb); 2241 if (ret != LDB_SUCCESS) { 1952 2242 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n", 1953 ldb_dn_get_linearized(msg->dn), 1954 ldb_errstring(ctx))); 2243 ldb_dn_get_linearized(user_dn), 2244 ldb_errstring(ldb))); 2245 talloc_free(user_dn); 1955 2246 return NT_STATUS_TRANSACTION_ABORTED; 1956 2247 } 2248 2249 talloc_free(user_dn); 1957 2250 return NT_STATUS_OK; 1958 2251 } 1959 1960 2252 1961 2253 … … 1965 2257 struct ldb_message *msg; 1966 2258 struct ldb_dn *basedn; 1967 c onst char *sidstr;2259 char *sidstr; 1968 2260 int ret; 1969 2261 … … 1974 2266 * is in our own domain */ 1975 2267 1976 msg = ldb_msg_new( mem_ctx);2268 msg = ldb_msg_new(sidstr); 1977 2269 if (msg == NULL) { 2270 talloc_free(sidstr); 1978 2271 return NT_STATUS_NO_MEMORY; 1979 2272 } 1980 2273 1981 /* TODO: Hmmm. This feels wrong. How do I find the base dn to 1982 * put the ForeignSecurityPrincipals? d_state->domain_dn does 1983 * not work, this is wrong for the Builtin domain, there's no 1984 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl 1985 */ 1986 1987 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL, 1988 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))"); 1989 1990 if (basedn == NULL) { 2274 ret = dsdb_wellknown_dn(sam_ctx, sidstr, 2275 ldb_get_default_basedn(sam_ctx), 2276 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER, 2277 &basedn); 2278 if (ret != LDB_SUCCESS) { 1991 2279 DEBUG(0, ("Failed to find DN for " 1992 "ForeignSecurityPrincipal container\n")); 2280 "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx))); 2281 talloc_free(sidstr); 1993 2282 return NT_STATUS_INTERNAL_DB_CORRUPTION; 1994 2283 } 1995 2284 1996 2285 /* add core elements to the ldb_message for the alias */ 1997 msg->dn = ldb_dn_copy(mem_ctx, basedn); 1998 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) 2286 msg->dn = basedn; 2287 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) { 2288 talloc_free(sidstr); 1999 2289 return NT_STATUS_NO_MEMORY; 2000 2001 samdb_msg_add_string(sam_ctx, mem_ctx, msg, 2002 "objectClass", 2003 "foreignSecurityPrincipal"); 2290 } 2291 2292 ret = ldb_msg_add_string(msg, "objectClass", 2293 "foreignSecurityPrincipal"); 2294 if (ret != LDB_SUCCESS) { 2295 talloc_free(sidstr); 2296 return NT_STATUS_NO_MEMORY; 2297 } 2004 2298 2005 2299 /* create the alias */ 2006 2300 ret = ldb_add(sam_ctx, msg); 2007 if (ret != 0) {2301 if (ret != LDB_SUCCESS) { 2008 2302 DEBUG(0,("Failed to create foreignSecurityPrincipal " 2009 2303 "record %s: %s\n", 2010 2304 ldb_dn_get_linearized(msg->dn), 2011 2305 ldb_errstring(sam_ctx))); 2306 talloc_free(sidstr); 2012 2307 return NT_STATUS_INTERNAL_DB_CORRUPTION; 2013 2308 } 2014 *ret_dn = msg->dn; 2309 2310 *ret_dn = talloc_steal(mem_ctx, msg->dn); 2311 talloc_free(sidstr); 2312 2015 2313 return NT_STATUS_OK; 2016 2314 } … … 2023 2321 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 2024 2322 { 2025 int i;2323 unsigned int i; 2026 2324 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 2027 2325 const char *binary_encoded; … … 2051 2349 DEBUG(2, ("Failed to validated DN %s\n", 2052 2350 ldb_dn_get_linearized(dn))); 2351 talloc_free(tmp_ctx); 2053 2352 return NULL; 2054 2353 } 2354 talloc_free(tmp_ctx); 2055 2355 return dn; 2056 2356 } 2357 2057 2358 /* 2058 2359 Find the DN of a domain, be it the netbios or DNS name 2059 2360 */ 2060 2061 2361 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 2062 2362 const char *domain_name) … … 2078 2378 "(&(nETBIOSName=%s)(objectclass=crossRef))", 2079 2379 escaped_domain); 2080 if (ret_domain != 0) {2380 if (ret_domain != LDB_SUCCESS) { 2081 2381 return NULL; 2082 2382 } … … 2089 2389 domain_ref2_attrs, 2090 2390 "(objectclass=domain)"); 2091 if (ret_domain != 0) {2391 if (ret_domain != LDB_SUCCESS) { 2092 2392 return NULL; 2093 2393 } … … 2115 2415 int dsdb_find_dn_by_guid(struct ldb_context *ldb, 2116 2416 TALLOC_CTX *mem_ctx, 2117 const char *guid_str, struct ldb_dn **dn)2417 const struct GUID *guid, struct ldb_dn **dn) 2118 2418 { 2119 2419 int ret; 2120 2420 struct ldb_result *res; 2121 2421 const char *attrs[] = { NULL }; 2122 struct ldb_request *search_req; 2123 char *expression; 2124 struct ldb_search_options_control *options; 2125 2126 expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str); 2127 if (!expression) { 2128 DEBUG(0, (__location__ ": out of memory\n")); 2129 return LDB_ERR_OPERATIONS_ERROR; 2130 } 2131 2132 res = talloc_zero(mem_ctx, struct ldb_result); 2422 char *guid_str = GUID_string(mem_ctx, guid); 2423 2424 if (!guid_str) { 2425 return ldb_operr(ldb); 2426 } 2427 2428 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, 2429 DSDB_SEARCH_SEARCH_ALL_PARTITIONS | 2430 DSDB_SEARCH_SHOW_EXTENDED_DN | 2431 DSDB_SEARCH_ONE_ONLY, 2432 "objectGUID=%s", guid_str); 2433 talloc_free(guid_str); 2434 if (ret != LDB_SUCCESS) { 2435 return ret; 2436 } 2437 2438 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn); 2439 talloc_free(res); 2440 2441 return LDB_SUCCESS; 2442 } 2443 2444 /* 2445 use a DN to find a GUID with a given attribute name 2446 */ 2447 int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb, 2448 struct ldb_dn *dn, const char *attribute, 2449 struct GUID *guid) 2450 { 2451 int ret; 2452 struct ldb_result *res; 2453 const char *attrs[2]; 2454 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 2455 2456 attrs[0] = attribute; 2457 attrs[1] = NULL; 2458 2459 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, 2460 DSDB_SEARCH_SHOW_DELETED | 2461 DSDB_SEARCH_SHOW_RECYCLED); 2462 if (ret != LDB_SUCCESS) { 2463 talloc_free(tmp_ctx); 2464 return ret; 2465 } 2466 if (res->count < 1) { 2467 talloc_free(tmp_ctx); 2468 return LDB_ERR_NO_SUCH_OBJECT; 2469 } 2470 *guid = samdb_result_guid(res->msgs[0], attribute); 2471 talloc_free(tmp_ctx); 2472 return LDB_SUCCESS; 2473 } 2474 2475 /* 2476 use a DN to find a GUID 2477 */ 2478 int dsdb_find_guid_by_dn(struct ldb_context *ldb, 2479 struct ldb_dn *dn, struct GUID *guid) 2480 { 2481 return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid); 2482 } 2483 2484 2485 2486 /* 2487 adds the given GUID to the given ldb_message. This value is added 2488 for the given attr_name (may be either "objectGUID" or "parentGUID"). 2489 */ 2490 int dsdb_msg_add_guid(struct ldb_message *msg, 2491 struct GUID *guid, 2492 const char *attr_name) 2493 { 2494 int ret; 2495 struct ldb_val v; 2496 NTSTATUS status; 2497 TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid"); 2498 2499 status = GUID_to_ndr_blob(guid, tmp_ctx, &v); 2500 if (!NT_STATUS_IS_OK(status)) { 2501 ret = LDB_ERR_OPERATIONS_ERROR; 2502 goto done; 2503 } 2504 2505 ret = ldb_msg_add_steal_value(msg, attr_name, &v); 2506 if (ret != LDB_SUCCESS) { 2507 DEBUG(4,(__location__ ": Failed to add %s to the message\n", 2508 attr_name)); 2509 goto done; 2510 } 2511 2512 ret = LDB_SUCCESS; 2513 2514 done: 2515 talloc_free(tmp_ctx); 2516 return ret; 2517 2518 } 2519 2520 2521 /* 2522 use a DN to find a SID 2523 */ 2524 int dsdb_find_sid_by_dn(struct ldb_context *ldb, 2525 struct ldb_dn *dn, struct dom_sid *sid) 2526 { 2527 int ret; 2528 struct ldb_result *res; 2529 const char *attrs[] = { "objectSid", NULL }; 2530 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 2531 struct dom_sid *s; 2532 2533 ZERO_STRUCTP(sid); 2534 2535 ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, 2536 DSDB_SEARCH_SHOW_DELETED | 2537 DSDB_SEARCH_SHOW_RECYCLED); 2538 if (ret != LDB_SUCCESS) { 2539 talloc_free(tmp_ctx); 2540 return ret; 2541 } 2542 if (res->count < 1) { 2543 talloc_free(tmp_ctx); 2544 return LDB_ERR_NO_SUCH_OBJECT; 2545 } 2546 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid"); 2547 if (s == NULL) { 2548 talloc_free(tmp_ctx); 2549 return LDB_ERR_NO_SUCH_OBJECT; 2550 } 2551 *sid = *s; 2552 talloc_free(tmp_ctx); 2553 return LDB_SUCCESS; 2554 } 2555 2556 /* 2557 use a SID to find a DN 2558 */ 2559 int dsdb_find_dn_by_sid(struct ldb_context *ldb, 2560 TALLOC_CTX *mem_ctx, 2561 struct dom_sid *sid, struct ldb_dn **dn) 2562 { 2563 int ret; 2564 struct ldb_result *res; 2565 const char *attrs[] = { NULL }; 2566 char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid); 2567 2568 if (!sid_str) { 2569 return ldb_operr(ldb); 2570 } 2571 2572 ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, 2573 DSDB_SEARCH_SEARCH_ALL_PARTITIONS | 2574 DSDB_SEARCH_SHOW_EXTENDED_DN | 2575 DSDB_SEARCH_ONE_ONLY, 2576 "objectSid=%s", sid_str); 2577 talloc_free(sid_str); 2578 if (ret != LDB_SUCCESS) { 2579 return ret; 2580 } 2581 2582 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn); 2583 talloc_free(res); 2584 2585 return LDB_SUCCESS; 2586 } 2587 2588 /* 2589 load a repsFromTo blob list for a given partition GUID 2590 attr must be "repsFrom" or "repsTo" 2591 */ 2592 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, 2593 const char *attr, struct repsFromToBlob **r, uint32_t *count) 2594 { 2595 const char *attrs[] = { attr, NULL }; 2596 struct ldb_result *res = NULL; 2597 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 2598 unsigned int i; 2599 struct ldb_message_element *el; 2600 2601 *r = NULL; 2602 *count = 0; 2603 2604 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS || 2605 res->count < 1) { 2606 DEBUG(0,("dsdb_loadreps: failed to read partition object\n")); 2607 talloc_free(tmp_ctx); 2608 return WERR_DS_DRA_INTERNAL_ERROR; 2609 } 2610 2611 el = ldb_msg_find_element(res->msgs[0], attr); 2612 if (el == NULL) { 2613 /* it's OK to be empty */ 2614 talloc_free(tmp_ctx); 2615 return WERR_OK; 2616 } 2617 2618 *count = el->num_values; 2619 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count); 2620 if (*r == NULL) { 2621 talloc_free(tmp_ctx); 2622 return WERR_DS_DRA_INTERNAL_ERROR; 2623 } 2624 2625 for (i=0; i<(*count); i++) { 2626 enum ndr_err_code ndr_err; 2627 ndr_err = ndr_pull_struct_blob(&el->values[i], 2628 mem_ctx, 2629 &(*r)[i], 2630 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob); 2631 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 2632 talloc_free(tmp_ctx); 2633 return WERR_DS_DRA_INTERNAL_ERROR; 2634 } 2635 } 2636 2637 talloc_free(tmp_ctx); 2638 2639 return WERR_OK; 2640 } 2641 2642 /* 2643 save the repsFromTo blob list for a given partition GUID 2644 attr must be "repsFrom" or "repsTo" 2645 */ 2646 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, 2647 const char *attr, struct repsFromToBlob *r, uint32_t count) 2648 { 2649 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 2650 struct ldb_message *msg; 2651 struct ldb_message_element *el; 2652 unsigned int i; 2653 2654 msg = ldb_msg_new(tmp_ctx); 2655 msg->dn = dn; 2656 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) { 2657 goto failed; 2658 } 2659 2660 el->values = talloc_array(msg, struct ldb_val, count); 2661 if (!el->values) { 2662 goto failed; 2663 } 2664 2665 for (i=0; i<count; i++) { 2666 struct ldb_val v; 2667 enum ndr_err_code ndr_err; 2668 2669 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, 2670 &r[i], 2671 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob); 2672 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 2673 goto failed; 2674 } 2675 2676 el->num_values++; 2677 el->values[i] = v; 2678 } 2679 2680 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) { 2681 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx))); 2682 goto failed; 2683 } 2684 2685 talloc_free(tmp_ctx); 2686 2687 return WERR_OK; 2688 2689 failed: 2690 talloc_free(tmp_ctx); 2691 return WERR_DS_DRA_INTERNAL_ERROR; 2692 } 2693 2694 2695 /* 2696 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED 2697 object for a partition 2698 */ 2699 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, 2700 uint64_t *uSN, uint64_t *urgent_uSN) 2701 { 2702 struct ldb_request *req; 2703 int ret; 2704 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 2705 struct dsdb_control_current_partition *p_ctrl; 2706 struct ldb_result *res; 2707 2708 res = talloc_zero(tmp_ctx, struct ldb_result); 2133 2709 if (!res) { 2134 DEBUG(0, (__location__ ": out of memory\n"));2135 return LDB_ERR_OPERATIONS_ERROR;2136 } 2137 2138 ret = ldb_build_search_req(& search_req, ldb, mem_ctx,2139 ldb_ get_default_basedn(ldb),2140 LDB_SCOPE_ SUBTREE,2141 expression, attrs,2710 talloc_free(tmp_ctx); 2711 return ldb_oom(ldb); 2712 } 2713 2714 ret = ldb_build_search_req(&req, ldb, tmp_ctx, 2715 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"), 2716 LDB_SCOPE_BASE, 2717 NULL, NULL, 2142 2718 NULL, 2143 2719 res, ldb_search_default_callback, 2144 2720 NULL); 2145 2721 if (ret != LDB_SUCCESS) { 2722 talloc_free(tmp_ctx); 2146 2723 return ret; 2147 2724 } 2148 2725 2149 /* we need to cope with cross-partition links, so search for 2150 the GUID over all partitions */ 2151 options = talloc(search_req, struct ldb_search_options_control); 2152 if (options == NULL) { 2153 DEBUG(0, (__location__ ": out of memory\n")); 2154 return LDB_ERR_OPERATIONS_ERROR; 2155 } 2156 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT; 2157 2158 ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL); 2159 if (ret != LDB_SUCCESS) { 2726 p_ctrl = talloc(req, struct dsdb_control_current_partition); 2727 if (p_ctrl == NULL) { 2728 talloc_free(tmp_ctx); 2729 return ldb_oom(ldb); 2730 } 2731 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION; 2732 p_ctrl->dn = dn; 2733 2734 ret = ldb_request_add_control(req, 2735 DSDB_CONTROL_CURRENT_PARTITION_OID, 2736 false, p_ctrl); 2737 if (ret != LDB_SUCCESS) { 2738 talloc_free(tmp_ctx); 2160 2739 return ret; 2161 2740 } 2162 2163 ret = ldb_request_add_control(search_req, 2164 LDB_CONTROL_SEARCH_OPTIONS_OID, 2165 true, options); 2166 if (ret != LDB_SUCCESS) { 2741 2742 /* Run the new request */ 2743 ret = ldb_request(ldb, req); 2744 2745 if (ret == LDB_SUCCESS) { 2746 ret = ldb_wait(req->handle, LDB_WAIT_ALL); 2747 } 2748 2749 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) { 2750 /* it hasn't been created yet, which means 2751 an implicit value of zero */ 2752 *uSN = 0; 2753 talloc_free(tmp_ctx); 2754 return LDB_SUCCESS; 2755 } 2756 2757 if (ret != LDB_SUCCESS) { 2758 talloc_free(tmp_ctx); 2167 2759 return ret; 2168 2760 } 2169 2761 2170 ret = ldb_request(ldb, search_req); 2171 if (ret != LDB_SUCCESS) { 2762 if (res->count < 1) { 2763 *uSN = 0; 2764 if (urgent_uSN) { 2765 *urgent_uSN = 0; 2766 } 2767 } else { 2768 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0); 2769 if (urgent_uSN) { 2770 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0); 2771 } 2772 } 2773 2774 talloc_free(tmp_ctx); 2775 2776 return LDB_SUCCESS; 2777 } 2778 2779 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1, 2780 const struct drsuapi_DsReplicaCursor2 *c2) 2781 { 2782 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id); 2783 } 2784 2785 int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1, 2786 const struct drsuapi_DsReplicaCursor *c2) 2787 { 2788 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id); 2789 } 2790 2791 2792 /* 2793 see if a computer identified by its invocationId is a RODC 2794 */ 2795 int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc) 2796 { 2797 /* 1) find the DN for this servers NTDSDSA object 2798 2) search for the msDS-isRODC attribute 2799 3) if not present then not a RODC 2800 4) if present and TRUE then is a RODC 2801 */ 2802 struct ldb_dn *config_dn; 2803 const char *attrs[] = { "msDS-isRODC", NULL }; 2804 int ret; 2805 struct ldb_result *res; 2806 TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx); 2807 2808 config_dn = ldb_get_config_basedn(sam_ctx); 2809 if (!config_dn) { 2810 talloc_free(tmp_ctx); 2811 return ldb_operr(sam_ctx); 2812 } 2813 2814 ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs, 2815 DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID)); 2816 2817 if (ret == LDB_ERR_NO_SUCH_OBJECT) { 2818 *is_rodc = false; 2819 talloc_free(tmp_ctx); 2820 return LDB_SUCCESS; 2821 } 2822 2823 if (ret != LDB_SUCCESS) { 2824 DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"), 2825 GUID_string(tmp_ctx, objectGUID))); 2826 *is_rodc = false; 2827 talloc_free(tmp_ctx); 2172 2828 return ret; 2173 2829 } 2174 2830 2175 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL); 2831 ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0); 2832 *is_rodc = (ret == 1); 2833 2834 talloc_free(tmp_ctx); 2835 return LDB_SUCCESS; 2836 } 2837 2838 2839 /* 2840 see if we are a RODC 2841 */ 2842 int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc) 2843 { 2844 const struct GUID *objectGUID; 2845 int ret; 2846 bool *cached; 2847 2848 /* see if we have a cached copy */ 2849 cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc"); 2850 if (cached) { 2851 *am_rodc = *cached; 2852 return LDB_SUCCESS; 2853 } 2854 2855 objectGUID = samdb_ntds_objectGUID(sam_ctx); 2856 if (!objectGUID) { 2857 return ldb_operr(sam_ctx); 2858 } 2859 2860 ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc); 2176 2861 if (ret != LDB_SUCCESS) { 2177 2862 return ret; 2178 2863 } 2179 2864 2180 /* this really should be exactly 1, but there is a bug in the 2181 partitions module that can return two here with the 2182 search_options control set */ 2183 if (res->count < 1) { 2865 cached = talloc(sam_ctx, bool); 2866 if (cached == NULL) { 2867 return ldb_oom(sam_ctx); 2868 } 2869 *cached = *am_rodc; 2870 2871 ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached); 2872 if (ret != LDB_SUCCESS) { 2873 talloc_free(cached); 2874 return ldb_operr(sam_ctx); 2875 } 2876 2877 return LDB_SUCCESS; 2878 } 2879 2880 bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc) 2881 { 2882 TALLOC_CTX *tmp_ctx; 2883 bool *cached; 2884 2885 tmp_ctx = talloc_new(ldb); 2886 if (tmp_ctx == NULL) { 2887 goto failed; 2888 } 2889 2890 cached = talloc(tmp_ctx, bool); 2891 if (!cached) { 2892 goto failed; 2893 } 2894 2895 *cached = am_rodc; 2896 if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) { 2897 goto failed; 2898 } 2899 2900 talloc_steal(ldb, cached); 2901 talloc_free(tmp_ctx); 2902 return true; 2903 2904 failed: 2905 DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n")); 2906 talloc_free(tmp_ctx); 2907 return false; 2908 } 2909 2910 2911 /* 2912 return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 2913 2914 flags are DS_NTDS_OPTION_* 2915 */ 2916 int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options) 2917 { 2918 TALLOC_CTX *tmp_ctx; 2919 const char *attrs[] = { "options", NULL }; 2920 int ret; 2921 struct ldb_result *res; 2922 2923 tmp_ctx = talloc_new(ldb); 2924 if (tmp_ctx == NULL) { 2925 goto failed; 2926 } 2927 2928 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); 2929 if (ret != LDB_SUCCESS) { 2930 goto failed; 2931 } 2932 2933 if (res->count != 1) { 2934 goto failed; 2935 } 2936 2937 *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0); 2938 2939 talloc_free(tmp_ctx); 2940 2941 return LDB_SUCCESS; 2942 2943 failed: 2944 DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n")); 2945 talloc_free(tmp_ctx); 2946 return LDB_ERR_NO_SUCH_OBJECT; 2947 } 2948 2949 const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb) 2950 { 2951 const char *attrs[] = { "objectCategory", NULL }; 2952 int ret; 2953 struct ldb_result *res; 2954 2955 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); 2956 if (ret != LDB_SUCCESS) { 2957 goto failed; 2958 } 2959 2960 if (res->count != 1) { 2961 goto failed; 2962 } 2963 2964 return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL); 2965 2966 failed: 2967 DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n")); 2968 return NULL; 2969 } 2970 2971 /* 2972 * Function which generates a "lDAPDisplayName" attribute from a "CN" one. 2973 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4 2974 */ 2975 const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn) 2976 { 2977 char **tokens, *ret; 2978 size_t i; 2979 2980 tokens = str_list_make(mem_ctx, cn, " -_"); 2981 if (tokens == NULL) 2982 return NULL; 2983 2984 /* "tolower()" and "toupper()" should also work properly on 0x00 */ 2985 tokens[0][0] = tolower(tokens[0][0]); 2986 for (i = 1; i < str_list_length((const char **)tokens); i++) 2987 tokens[i][0] = toupper(tokens[i][0]); 2988 2989 ret = talloc_strdup(mem_ctx, tokens[0]); 2990 for (i = 1; i < str_list_length((const char **)tokens); i++) 2991 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]); 2992 2993 talloc_free(tokens); 2994 2995 return ret; 2996 } 2997 2998 /* 2999 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*) 3000 */ 3001 int dsdb_functional_level(struct ldb_context *ldb) 3002 { 3003 int *domainFunctionality = 3004 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int); 3005 if (!domainFunctionality) { 3006 /* this is expected during initial provision */ 3007 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n")); 3008 return DS_DOMAIN_FUNCTION_2000; 3009 } 3010 return *domainFunctionality; 3011 } 3012 3013 /* 3014 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*) 3015 */ 3016 int dsdb_forest_functional_level(struct ldb_context *ldb) 3017 { 3018 int *forestFunctionality = 3019 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int); 3020 if (!forestFunctionality) { 3021 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n")); 3022 return DS_DOMAIN_FUNCTION_2000; 3023 } 3024 return *forestFunctionality; 3025 } 3026 3027 /* 3028 set a GUID in an extended DN structure 3029 */ 3030 int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name) 3031 { 3032 struct ldb_val v; 3033 NTSTATUS status; 3034 int ret; 3035 3036 status = GUID_to_ndr_blob(guid, dn, &v); 3037 if (!NT_STATUS_IS_OK(status)) { 3038 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; 3039 } 3040 3041 ret = ldb_dn_set_extended_component(dn, component_name, &v); 3042 data_blob_free(&v); 3043 return ret; 3044 } 3045 3046 /* 3047 return a GUID from a extended DN structure 3048 */ 3049 NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name) 3050 { 3051 const struct ldb_val *v; 3052 3053 v = ldb_dn_get_extended_component(dn, component_name); 3054 if (v == NULL) { 3055 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 3056 } 3057 3058 return GUID_from_ndr_blob(v, guid); 3059 } 3060 3061 /* 3062 return a uint64_t from a extended DN structure 3063 */ 3064 NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name) 3065 { 3066 const struct ldb_val *v; 3067 char *s; 3068 3069 v = ldb_dn_get_extended_component(dn, component_name); 3070 if (v == NULL) { 3071 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 3072 } 3073 s = talloc_strndup(dn, (const char *)v->data, v->length); 3074 NT_STATUS_HAVE_NO_MEMORY(s); 3075 3076 *val = strtoull(s, NULL, 0); 3077 3078 talloc_free(s); 3079 return NT_STATUS_OK; 3080 } 3081 3082 /* 3083 return a NTTIME from a extended DN structure 3084 */ 3085 NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name) 3086 { 3087 return dsdb_get_extended_dn_uint64(dn, nttime, component_name); 3088 } 3089 3090 /* 3091 return a uint32_t from a extended DN structure 3092 */ 3093 NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name) 3094 { 3095 const struct ldb_val *v; 3096 char *s; 3097 3098 v = ldb_dn_get_extended_component(dn, component_name); 3099 if (v == NULL) { 3100 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 3101 } 3102 3103 s = talloc_strndup(dn, (const char *)v->data, v->length); 3104 NT_STATUS_HAVE_NO_MEMORY(s); 3105 3106 *val = strtoul(s, NULL, 0); 3107 3108 talloc_free(s); 3109 return NT_STATUS_OK; 3110 } 3111 3112 /* 3113 return a dom_sid from a extended DN structure 3114 */ 3115 NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name) 3116 { 3117 const struct ldb_val *sid_blob; 3118 struct TALLOC_CTX *tmp_ctx; 3119 enum ndr_err_code ndr_err; 3120 3121 sid_blob = ldb_dn_get_extended_component(dn, component_name); 3122 if (!sid_blob) { 3123 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 3124 } 3125 3126 tmp_ctx = talloc_new(NULL); 3127 3128 ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid, 3129 (ndr_pull_flags_fn_t)ndr_pull_dom_sid); 3130 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 3131 NTSTATUS status = ndr_map_error2ntstatus(ndr_err); 3132 talloc_free(tmp_ctx); 3133 return status; 3134 } 3135 3136 talloc_free(tmp_ctx); 3137 return NT_STATUS_OK; 3138 } 3139 3140 3141 /* 3142 return RMD_FLAGS directly from a ldb_dn 3143 returns 0 if not found 3144 */ 3145 uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn) 3146 { 3147 const struct ldb_val *v; 3148 char buf[32]; 3149 v = ldb_dn_get_extended_component(dn, "RMD_FLAGS"); 3150 if (!v || v->length > sizeof(buf)-1) return 0; 3151 strncpy(buf, (const char *)v->data, v->length); 3152 buf[v->length] = 0; 3153 return strtoul(buf, NULL, 10); 3154 } 3155 3156 /* 3157 return RMD_FLAGS directly from a ldb_val for a DN 3158 returns 0 if RMD_FLAGS is not found 3159 */ 3160 uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val) 3161 { 3162 const char *p; 3163 uint32_t flags; 3164 char *end; 3165 3166 if (val->length < 13) { 3167 return 0; 3168 } 3169 p = memmem(val->data, val->length, "<RMD_FLAGS=", 11); 3170 if (!p) { 3171 return 0; 3172 } 3173 flags = strtoul(p+11, &end, 10); 3174 if (!end || *end != '>') { 3175 /* it must end in a > */ 3176 return 0; 3177 } 3178 return flags; 3179 } 3180 3181 /* 3182 return true if a ldb_val containing a DN in storage form is deleted 3183 */ 3184 bool dsdb_dn_is_deleted_val(const struct ldb_val *val) 3185 { 3186 return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0; 3187 } 3188 3189 /* 3190 return true if a ldb_val containing a DN in storage form is 3191 in the upgraded w2k3 linked attribute format 3192 */ 3193 bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val) 3194 { 3195 return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL; 3196 } 3197 3198 /* 3199 return a DN for a wellknown GUID 3200 */ 3201 int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, 3202 struct ldb_dn *nc_root, const char *wk_guid, 3203 struct ldb_dn **wkguid_dn) 3204 { 3205 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 3206 const char *attrs[] = { NULL }; 3207 int ret; 3208 struct ldb_dn *dn; 3209 struct ldb_result *res; 3210 3211 /* construct the magic WKGUID DN */ 3212 dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>", 3213 wk_guid, ldb_dn_get_linearized(nc_root)); 3214 if (!wkguid_dn) { 3215 talloc_free(tmp_ctx); 3216 return ldb_operr(samdb); 3217 } 3218 3219 ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, 3220 DSDB_SEARCH_SHOW_DELETED | 3221 DSDB_SEARCH_SHOW_RECYCLED); 3222 if (ret != LDB_SUCCESS) { 3223 talloc_free(tmp_ctx); 3224 return ret; 3225 } 3226 3227 (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn); 3228 talloc_free(tmp_ctx); 3229 return LDB_SUCCESS; 3230 } 3231 3232 3233 static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2) 3234 { 3235 return ldb_dn_compare(*dn1, *dn2); 3236 } 3237 3238 /* 3239 find a NC root given a DN within the NC 3240 */ 3241 int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, 3242 struct ldb_dn **nc_root) 3243 { 3244 const char *root_attrs[] = { "namingContexts", NULL }; 3245 TALLOC_CTX *tmp_ctx; 3246 int ret; 3247 struct ldb_message_element *el; 3248 struct ldb_result *root_res; 3249 unsigned int i; 3250 struct ldb_dn **nc_dns; 3251 3252 tmp_ctx = talloc_new(samdb); 3253 if (tmp_ctx == NULL) { 3254 return ldb_oom(samdb); 3255 } 3256 3257 ret = ldb_search(samdb, tmp_ctx, &root_res, 3258 ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL); 3259 if (ret != LDB_SUCCESS) { 3260 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb))); 3261 talloc_free(tmp_ctx); 3262 return ret; 3263 } 3264 3265 el = ldb_msg_find_element(root_res->msgs[0], "namingContexts"); 3266 if ((el == NULL) || (el->num_values < 3)) { 3267 struct ldb_message *tmp_msg; 3268 3269 DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list.")); 3270 3271 /* This generates a temporary list of NCs in order to let the 3272 * provisioning work. */ 3273 tmp_msg = ldb_msg_new(tmp_ctx); 3274 if (tmp_msg == NULL) { 3275 talloc_free(tmp_ctx); 3276 return ldb_oom(samdb); 3277 } 3278 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts", 3279 ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb))); 3280 if (ret != LDB_SUCCESS) { 3281 talloc_free(tmp_ctx); 3282 return ret; 3283 } 3284 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts", 3285 ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb))); 3286 if (ret != LDB_SUCCESS) { 3287 talloc_free(tmp_ctx); 3288 return ret; 3289 } 3290 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts", 3291 ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb))); 3292 if (ret != LDB_SUCCESS) { 3293 talloc_free(tmp_ctx); 3294 return ret; 3295 } 3296 el = &tmp_msg->elements[0]; 3297 } 3298 3299 nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values); 3300 if (!nc_dns) { 3301 talloc_free(tmp_ctx); 3302 return ldb_oom(samdb); 3303 } 3304 3305 for (i=0; i<el->num_values; i++) { 3306 nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]); 3307 if (nc_dns[i] == NULL) { 3308 talloc_free(tmp_ctx); 3309 return ldb_operr(samdb); 3310 } 3311 } 3312 3313 TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs); 3314 3315 for (i=0; i<el->num_values; i++) { 3316 if (ldb_dn_compare_base(nc_dns[i], dn) == 0) { 3317 (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]); 3318 talloc_free(tmp_ctx); 3319 return LDB_SUCCESS; 3320 } 3321 } 3322 3323 talloc_free(tmp_ctx); 3324 return LDB_ERR_NO_SUCH_OBJECT; 3325 } 3326 3327 3328 /* 3329 find the deleted objects DN for any object, by looking for the NC 3330 root, then looking up the wellknown GUID 3331 */ 3332 int dsdb_get_deleted_objects_dn(struct ldb_context *ldb, 3333 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn, 3334 struct ldb_dn **do_dn) 3335 { 3336 struct ldb_dn *nc_root; 3337 int ret; 3338 3339 ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root); 3340 if (ret != LDB_SUCCESS) { 3341 return ret; 3342 } 3343 3344 ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn); 3345 talloc_free(nc_root); 3346 return ret; 3347 } 3348 3349 /* 3350 return the tombstoneLifetime, in days 3351 */ 3352 int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime) 3353 { 3354 struct ldb_dn *dn; 3355 dn = ldb_get_config_basedn(ldb); 3356 if (!dn) { 2184 3357 return LDB_ERR_NO_SUCH_OBJECT; 2185 3358 } 2186 2187 *dn = res->msgs[0]->dn; 2188 3359 dn = ldb_dn_copy(ldb, dn); 3360 if (!dn) { 3361 return ldb_operr(ldb); 3362 } 3363 /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to 3364 be a wellknown GUID for this */ 3365 if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) { 3366 talloc_free(dn); 3367 return ldb_operr(ldb); 3368 } 3369 3370 *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService"); 3371 talloc_free(dn); 2189 3372 return LDB_SUCCESS; 2190 3373 } 2191 3374 2192 3375 /* 2193 search for attrs on one DN, allowing for deleted objects 2194 */ 2195 int dsdb_search_dn_with_deleted(struct ldb_context *ldb, 2196 TALLOC_CTX *mem_ctx, 2197 struct ldb_result **_res, 2198 struct ldb_dn *basedn, 2199 const char * const *attrs) 2200 { 2201 int ret; 3376 compare a ldb_val to a string case insensitively 3377 */ 3378 int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v) 3379 { 3380 size_t len = strlen(s); 3381 int ret; 3382 if (len > v->length) return 1; 3383 ret = strncasecmp(s, (const char *)v->data, v->length); 3384 if (ret != 0) return ret; 3385 if (v->length > len && v->data[len] != 0) { 3386 return -1; 3387 } 3388 return 0; 3389 } 3390 3391 3392 /* 3393 load the UDV for a partition in v2 format 3394 The list is returned sorted, and with our local cursor added 3395 */ 3396 int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx, 3397 struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count) 3398 { 3399 static const char *attrs[] = { "replUpToDateVector", NULL }; 3400 struct ldb_result *r; 3401 const struct ldb_val *ouv_value; 3402 unsigned int i; 3403 int ret; 3404 uint64_t highest_usn; 3405 const struct GUID *our_invocation_id; 3406 struct timeval now = timeval_current(); 3407 3408 ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL); 3409 if (ret != LDB_SUCCESS) { 3410 return ret; 3411 } 3412 3413 ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector"); 3414 if (ouv_value) { 3415 enum ndr_err_code ndr_err; 3416 struct replUpToDateVectorBlob ouv; 3417 3418 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv, 3419 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob); 3420 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 3421 talloc_free(r); 3422 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; 3423 } 3424 if (ouv.version != 2) { 3425 /* we always store as version 2, and 3426 * replUpToDateVector is not replicated 3427 */ 3428 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; 3429 } 3430 3431 *count = ouv.ctr.ctr2.count; 3432 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors); 3433 } else { 3434 *count = 0; 3435 *cursors = NULL; 3436 } 3437 3438 talloc_free(r); 3439 3440 our_invocation_id = samdb_ntds_invocation_id(samdb); 3441 if (!our_invocation_id) { 3442 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb))); 3443 talloc_free(*cursors); 3444 return ldb_operr(samdb); 3445 } 3446 3447 ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL); 3448 if (ret != LDB_SUCCESS) { 3449 /* nothing to add - this can happen after a vampire */ 3450 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare); 3451 return LDB_SUCCESS; 3452 } 3453 3454 for (i=0; i<*count; i++) { 3455 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) { 3456 (*cursors)[i].highest_usn = highest_usn; 3457 (*cursors)[i].last_sync_success = timeval_to_nttime(&now); 3458 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare); 3459 return LDB_SUCCESS; 3460 } 3461 } 3462 3463 (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1); 3464 if (! *cursors) { 3465 return ldb_oom(samdb); 3466 } 3467 3468 (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id; 3469 (*cursors)[*count].highest_usn = highest_usn; 3470 (*cursors)[*count].last_sync_success = timeval_to_nttime(&now); 3471 (*count)++; 3472 3473 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare); 3474 3475 return LDB_SUCCESS; 3476 } 3477 3478 /* 3479 load the UDV for a partition in version 1 format 3480 The list is returned sorted, and with our local cursor added 3481 */ 3482 int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx, 3483 struct drsuapi_DsReplicaCursor **cursors, uint32_t *count) 3484 { 3485 struct drsuapi_DsReplicaCursor2 *v2; 3486 uint32_t i; 3487 int ret; 3488 3489 ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count); 3490 if (ret != LDB_SUCCESS) { 3491 return ret; 3492 } 3493 3494 if (*count == 0) { 3495 talloc_free(v2); 3496 *cursors = NULL; 3497 return LDB_SUCCESS; 3498 } 3499 3500 *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count); 3501 if (*cursors == NULL) { 3502 talloc_free(v2); 3503 return ldb_oom(samdb); 3504 } 3505 3506 for (i=0; i<*count; i++) { 3507 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id; 3508 (*cursors)[i].highest_usn = v2[i].highest_usn; 3509 } 3510 talloc_free(v2); 3511 return LDB_SUCCESS; 3512 } 3513 3514 /* 3515 add a set of controls to a ldb_request structure based on a set of 3516 flags. See util.h for a list of available flags 3517 */ 3518 int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags) 3519 { 3520 int ret; 3521 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) { 3522 struct ldb_search_options_control *options; 3523 /* Using the phantom root control allows us to search all partitions */ 3524 options = talloc(req, struct ldb_search_options_control); 3525 if (options == NULL) { 3526 return LDB_ERR_OPERATIONS_ERROR; 3527 } 3528 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT; 3529 3530 ret = ldb_request_add_control(req, 3531 LDB_CONTROL_SEARCH_OPTIONS_OID, 3532 true, options); 3533 if (ret != LDB_SUCCESS) { 3534 return ret; 3535 } 3536 } 3537 3538 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) { 3539 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL); 3540 if (ret != LDB_SUCCESS) { 3541 return ret; 3542 } 3543 } 3544 3545 if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) { 3546 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL); 3547 if (ret != LDB_SUCCESS) { 3548 return ret; 3549 } 3550 } 3551 3552 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) { 3553 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL); 3554 if (ret != LDB_SUCCESS) { 3555 return ret; 3556 } 3557 } 3558 3559 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) { 3560 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control); 3561 if (!extended_ctrl) { 3562 return LDB_ERR_OPERATIONS_ERROR; 3563 } 3564 extended_ctrl->type = 1; 3565 3566 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl); 3567 if (ret != LDB_SUCCESS) { 3568 return ret; 3569 } 3570 } 3571 3572 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) { 3573 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL); 3574 if (ret != LDB_SUCCESS) { 3575 return ret; 3576 } 3577 } 3578 3579 if (dsdb_flags & DSDB_MODIFY_RELAX) { 3580 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL); 3581 if (ret != LDB_SUCCESS) { 3582 return ret; 3583 } 3584 } 3585 3586 if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) { 3587 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL); 3588 if (ret != LDB_SUCCESS) { 3589 return ret; 3590 } 3591 } 3592 3593 if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) { 3594 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL); 3595 if (ret != LDB_SUCCESS) { 3596 return ret; 3597 } 3598 } 3599 3600 if (dsdb_flags & DSDB_TREE_DELETE) { 3601 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL); 3602 if (ret != LDB_SUCCESS) { 3603 return ret; 3604 } 3605 } 3606 3607 if (dsdb_flags & DSDB_PROVISION) { 3608 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL); 3609 if (ret != LDB_SUCCESS) { 3610 return ret; 3611 } 3612 } 3613 3614 return LDB_SUCCESS; 3615 } 3616 3617 /* 3618 an add with a set of controls 3619 */ 3620 int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message, 3621 uint32_t dsdb_flags) 3622 { 2202 3623 struct ldb_request *req; 2203 TALLOC_CTX *tmp_ctx; 3624 int ret; 3625 3626 ret = ldb_build_add_req(&req, ldb, ldb, 3627 message, 3628 NULL, 3629 NULL, 3630 ldb_op_default_callback, 3631 NULL); 3632 3633 if (ret != LDB_SUCCESS) return ret; 3634 3635 ret = dsdb_request_add_controls(req, dsdb_flags); 3636 if (ret != LDB_SUCCESS) { 3637 talloc_free(req); 3638 return ret; 3639 } 3640 3641 ret = dsdb_autotransaction_request(ldb, req); 3642 3643 talloc_free(req); 3644 return ret; 3645 } 3646 3647 /* 3648 a modify with a set of controls 3649 */ 3650 int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message, 3651 uint32_t dsdb_flags) 3652 { 3653 struct ldb_request *req; 3654 int ret; 3655 3656 ret = ldb_build_mod_req(&req, ldb, ldb, 3657 message, 3658 NULL, 3659 NULL, 3660 ldb_op_default_callback, 3661 NULL); 3662 3663 if (ret != LDB_SUCCESS) return ret; 3664 3665 ret = dsdb_request_add_controls(req, dsdb_flags); 3666 if (ret != LDB_SUCCESS) { 3667 talloc_free(req); 3668 return ret; 3669 } 3670 3671 ret = dsdb_autotransaction_request(ldb, req); 3672 3673 talloc_free(req); 3674 return ret; 3675 } 3676 3677 /* 3678 like dsdb_modify() but set all the element flags to 3679 LDB_FLAG_MOD_REPLACE 3680 */ 3681 int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags) 3682 { 3683 unsigned int i; 3684 3685 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */ 3686 for (i=0;i<msg->num_elements;i++) { 3687 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; 3688 } 3689 3690 return dsdb_modify(ldb, msg, dsdb_flags); 3691 } 3692 3693 3694 /* 3695 search for attrs on one DN, allowing for dsdb_flags controls 3696 */ 3697 int dsdb_search_dn(struct ldb_context *ldb, 3698 TALLOC_CTX *mem_ctx, 3699 struct ldb_result **_res, 3700 struct ldb_dn *basedn, 3701 const char * const *attrs, 3702 uint32_t dsdb_flags) 3703 { 3704 int ret; 3705 struct ldb_request *req; 2204 3706 struct ldb_result *res; 2205 3707 2206 tmp_ctx = talloc_new(mem_ctx); 2207 2208 res = talloc_zero(tmp_ctx, struct ldb_result); 3708 res = talloc_zero(mem_ctx, struct ldb_result); 2209 3709 if (!res) { 2210 return LDB_ERR_OPERATIONS_ERROR;2211 } 2212 2213 ret = ldb_build_search_req(&req, ldb, tmp_ctx,3710 return ldb_oom(ldb); 3711 } 3712 3713 ret = ldb_build_search_req(&req, ldb, res, 2214 3714 basedn, 2215 3715 LDB_SCOPE_BASE, … … 2221 3721 NULL); 2222 3722 if (ret != LDB_SUCCESS) { 2223 talloc_free( tmp_ctx);3723 talloc_free(res); 2224 3724 return ret; 2225 3725 } 2226 3726 2227 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL); 2228 if (ret != LDB_SUCCESS) { 3727 ret = dsdb_request_add_controls(req, dsdb_flags); 3728 if (ret != LDB_SUCCESS) { 3729 talloc_free(res); 2229 3730 return ret; 2230 3731 } … … 2236 3737 2237 3738 talloc_free(req); 2238 *_res = talloc_steal(mem_ctx, res); 3739 if (ret != LDB_SUCCESS) { 3740 talloc_free(res); 3741 return ret; 3742 } 3743 3744 *_res = res; 3745 return LDB_SUCCESS; 3746 } 3747 3748 /* 3749 search for attrs on one DN, by the GUID of the DN, allowing for 3750 dsdb_flags controls 3751 */ 3752 int dsdb_search_by_dn_guid(struct ldb_context *ldb, 3753 TALLOC_CTX *mem_ctx, 3754 struct ldb_result **_res, 3755 const struct GUID *guid, 3756 const char * const *attrs, 3757 uint32_t dsdb_flags) 3758 { 3759 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 3760 struct ldb_dn *dn; 3761 int ret; 3762 3763 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid)); 3764 if (dn == NULL) { 3765 talloc_free(tmp_ctx); 3766 return ldb_oom(ldb); 3767 } 3768 3769 ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags); 3770 talloc_free(tmp_ctx); 2239 3771 return ret; 2240 3772 } 2241 3773 2242 2243 /* 2244 use a DN to find a GUID 2245 */ 2246 int dsdb_find_guid_by_dn(struct ldb_context *ldb, 2247 struct ldb_dn *dn, struct GUID *guid) 2248 { 2249 int ret; 3774 /* 3775 general search with dsdb_flags for controls 3776 */ 3777 int dsdb_search(struct ldb_context *ldb, 3778 TALLOC_CTX *mem_ctx, 3779 struct ldb_result **_res, 3780 struct ldb_dn *basedn, 3781 enum ldb_scope scope, 3782 const char * const *attrs, 3783 uint32_t dsdb_flags, 3784 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9) 3785 { 3786 int ret; 3787 struct ldb_request *req; 2250 3788 struct ldb_result *res; 2251 const char *attrs[] = { "objectGUID", NULL }; 2252 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 2253 2254 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs); 2255 if (ret != LDB_SUCCESS) { 2256 talloc_free(tmp_ctx); 2257 return ret; 2258 } 2259 if (res->count < 1) { 2260 talloc_free(tmp_ctx); 2261 return LDB_ERR_NO_SUCH_OBJECT; 2262 } 2263 *guid = samdb_result_guid(res->msgs[0], "objectGUID"); 2264 talloc_free(tmp_ctx); 2265 return LDB_SUCCESS; 2266 } 2267 2268 /* 2269 use a DN to find a SID 2270 */ 2271 int dsdb_find_sid_by_dn(struct ldb_context *ldb, 2272 struct ldb_dn *dn, struct dom_sid *sid) 2273 { 2274 int ret; 2275 struct ldb_result *res; 2276 const char *attrs[] = { "objectSID", NULL }; 2277 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 2278 struct dom_sid *s; 2279 2280 ZERO_STRUCTP(sid); 2281 2282 ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs); 2283 if (ret != LDB_SUCCESS) { 2284 talloc_free(tmp_ctx); 2285 return ret; 2286 } 2287 if (res->count < 1) { 2288 talloc_free(tmp_ctx); 2289 return LDB_ERR_NO_SUCH_OBJECT; 2290 } 2291 s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID"); 2292 if (s == NULL) { 2293 talloc_free(tmp_ctx); 2294 return LDB_ERR_NO_SUCH_OBJECT; 2295 } 2296 *sid = *s; 2297 talloc_free(tmp_ctx); 2298 return LDB_SUCCESS; 2299 } 2300 2301 2302 2303 /* 2304 load a repsFromTo blob list for a given partition GUID 2305 attr must be "repsFrom" or "repsTo" 2306 */ 2307 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, 2308 const char *attr, struct repsFromToBlob **r, uint32_t *count) 2309 { 2310 const char *attrs[] = { attr, NULL }; 2311 struct ldb_result *res = NULL; 3789 va_list ap; 3790 char *expression = NULL; 2312 3791 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 2313 int i;2314 struct ldb_message_element *el;2315 2316 *r = NULL;2317 *count = 0;2318 2319 if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||2320 res->count < 1) {2321 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));2322 talloc_free(tmp_ctx);2323 return WERR_DS_DRA_INTERNAL_ERROR;2324 }2325 2326 el = ldb_msg_find_element(res->msgs[0], attr);2327 if (el == NULL) {2328 /* it's OK to be empty */2329 talloc_free(tmp_ctx);2330 return WERR_OK;2331 }2332 2333 *count = el->num_values;2334 *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);2335 if (*r == NULL) {2336 talloc_free(tmp_ctx);2337 return WERR_DS_DRA_INTERNAL_ERROR;2338 }2339 2340 for (i=0; i<(*count); i++) {2341 enum ndr_err_code ndr_err;2342 ndr_err = ndr_pull_struct_blob(&el->values[i],2343 mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),2344 &(*r)[i],2345 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);2346 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {2347 talloc_free(tmp_ctx);2348 return WERR_DS_DRA_INTERNAL_ERROR;2349 }2350 }2351 2352 talloc_free(tmp_ctx);2353 2354 return WERR_OK;2355 }2356 2357 /*2358 save the repsFromTo blob list for a given partition GUID2359 attr must be "repsFrom" or "repsTo"2360 */2361 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,2362 const char *attr, struct repsFromToBlob *r, uint32_t count)2363 {2364 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);2365 struct ldb_message *msg;2366 struct ldb_message_element *el;2367 int i;2368 2369 msg = ldb_msg_new(tmp_ctx);2370 msg->dn = dn;2371 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {2372 goto failed;2373 }2374 2375 el->values = talloc_array(msg, struct ldb_val, count);2376 if (!el->values) {2377 goto failed;2378 }2379 2380 for (i=0; i<count; i++) {2381 struct ldb_val v;2382 enum ndr_err_code ndr_err;2383 2384 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),2385 &r[i],2386 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);2387 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {2388 goto failed;2389 }2390 2391 el->num_values++;2392 el->values[i] = v;2393 }2394 2395 if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {2396 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));2397 goto failed;2398 }2399 2400 talloc_free(tmp_ctx);2401 2402 return WERR_OK;2403 2404 failed:2405 talloc_free(tmp_ctx);2406 return WERR_DS_DRA_INTERNAL_ERROR;2407 }2408 2409 2410 /*2411 load the uSNHighest attribute from the @REPLCHANGED object for a2412 partition2413 */2414 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)2415 {2416 struct ldb_request *req;2417 int ret;2418 TALLOC_CTX *tmp_ctx = talloc_new(ldb);2419 struct dsdb_control_current_partition *p_ctrl;2420 struct ldb_result *res;2421 3792 2422 3793 res = talloc_zero(tmp_ctx, struct ldb_result); 2423 3794 if (!res) { 2424 3795 talloc_free(tmp_ctx); 2425 return LDB_ERR_OPERATIONS_ERROR; 3796 return ldb_oom(ldb); 3797 } 3798 3799 if (exp_fmt) { 3800 va_start(ap, exp_fmt); 3801 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap); 3802 va_end(ap); 3803 3804 if (!expression) { 3805 talloc_free(tmp_ctx); 3806 return ldb_oom(ldb); 3807 } 2426 3808 } 2427 3809 2428 3810 ret = ldb_build_search_req(&req, ldb, tmp_ctx, 2429 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"), 2430 LDB_SCOPE_BASE, 2431 NULL, NULL, 3811 basedn, 3812 scope, 3813 expression, 3814 attrs, 2432 3815 NULL, 2433 res, ldb_search_default_callback, 3816 res, 3817 ldb_search_default_callback, 2434 3818 NULL); 2435 3819 if (ret != LDB_SUCCESS) { … … 2438 3822 } 2439 3823 2440 p_ctrl = talloc(req, struct dsdb_control_current_partition);2441 if ( p_ctrl == NULL) {2442 talloc_free( res);2443 return LDB_ERR_OPERATIONS_ERROR;2444 }2445 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;2446 p_ctrl->dn = dn; 2447 2448 2449 ret = ldb_request_add_control(req,2450 DSDB_CONTROL_CURRENT_PARTITION_OID,2451 false, p_ctrl); 3824 ret = dsdb_request_add_controls(req, dsdb_flags); 3825 if (ret != LDB_SUCCESS) { 3826 talloc_free(tmp_ctx); 3827 ldb_reset_err_string(ldb); 3828 return ret; 3829 } 3830 3831 ret = ldb_request(ldb, req); 3832 if (ret == LDB_SUCCESS) { 3833 ret = ldb_wait(req->handle, LDB_WAIT_ALL); 3834 } 3835 2452 3836 if (ret != LDB_SUCCESS) { 2453 3837 talloc_free(tmp_ctx); 2454 3838 return ret; 2455 3839 } 2456 2457 /* Run the new request */ 2458 ret = ldb_request(ldb, req); 2459 2460 if (ret == LDB_SUCCESS) { 2461 ret = ldb_wait(req->handle, LDB_WAIT_ALL); 2462 } 2463 2464 if (ret == LDB_ERR_NO_SUCH_OBJECT) { 2465 /* it hasn't been created yet, which means 2466 an implicit value of zero */ 2467 *uSN = 0; 3840 3841 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) { 3842 if (res->count == 0) { 3843 talloc_free(tmp_ctx); 3844 ldb_reset_err_string(ldb); 3845 return LDB_ERR_NO_SUCH_OBJECT; 3846 } 3847 if (res->count != 1) { 3848 talloc_free(tmp_ctx); 3849 ldb_reset_err_string(ldb); 3850 return LDB_ERR_CONSTRAINT_VIOLATION; 3851 } 3852 } 3853 3854 *_res = talloc_steal(mem_ctx, res); 3855 talloc_free(tmp_ctx); 3856 3857 return LDB_SUCCESS; 3858 } 3859 3860 3861 /* 3862 general search with dsdb_flags for controls 3863 returns exactly 1 record or an error 3864 */ 3865 int dsdb_search_one(struct ldb_context *ldb, 3866 TALLOC_CTX *mem_ctx, 3867 struct ldb_message **msg, 3868 struct ldb_dn *basedn, 3869 enum ldb_scope scope, 3870 const char * const *attrs, 3871 uint32_t dsdb_flags, 3872 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9) 3873 { 3874 int ret; 3875 struct ldb_result *res; 3876 va_list ap; 3877 char *expression = NULL; 3878 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 3879 3880 dsdb_flags |= DSDB_SEARCH_ONE_ONLY; 3881 3882 res = talloc_zero(tmp_ctx, struct ldb_result); 3883 if (!res) { 2468 3884 talloc_free(tmp_ctx); 2469 return LDB_SUCCESS; 3885 return ldb_oom(ldb); 3886 } 3887 3888 if (exp_fmt) { 3889 va_start(ap, exp_fmt); 3890 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap); 3891 va_end(ap); 3892 3893 if (!expression) { 3894 talloc_free(tmp_ctx); 3895 return ldb_oom(ldb); 3896 } 3897 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs, 3898 dsdb_flags, "%s", expression); 3899 } else { 3900 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs, 3901 dsdb_flags, NULL); 2470 3902 } 2471 3903 … … 2475 3907 } 2476 3908 2477 if (res->count < 1) { 2478 *uSN = 0; 2479 } else { 2480 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0); 2481 } 2482 3909 *msg = talloc_steal(mem_ctx, res->msgs[0]); 2483 3910 talloc_free(tmp_ctx); 2484 3911 2485 return LDB_SUCCESS; 2486 } 2487 2488 /* 2489 save the uSNHighest attribute in the @REPLCHANGED object for a 2490 partition 2491 */ 2492 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN) 2493 { 2494 struct ldb_request *req; 3912 return LDB_SUCCESS; 3913 } 3914 3915 /* returns back the forest DNS name */ 3916 const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 3917 { 3918 const char *forest_name = ldb_dn_canonical_string(mem_ctx, 3919 ldb_get_root_basedn(ldb)); 3920 char *p; 3921 3922 if (forest_name == NULL) { 3923 return NULL; 3924 } 3925 3926 p = strchr(forest_name, '/'); 3927 if (p) { 3928 *p = '\0'; 3929 } 3930 3931 return forest_name; 3932 } 3933 3934 /* returns back the default domain DNS name */ 3935 const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 3936 { 3937 const char *domain_name = ldb_dn_canonical_string(mem_ctx, 3938 ldb_get_default_basedn(ldb)); 3939 char *p; 3940 3941 if (domain_name == NULL) { 3942 return NULL; 3943 } 3944 3945 p = strchr(domain_name, '/'); 3946 if (p) { 3947 *p = '\0'; 3948 } 3949 3950 return domain_name; 3951 } 3952 3953 /* 3954 validate that an DSA GUID belongs to the specified user sid. 3955 The user SID must be a domain controller account (either RODC or 3956 RWDC) 3957 */ 3958 int dsdb_validate_dsa_guid(struct ldb_context *ldb, 3959 const struct GUID *dsa_guid, 3960 const struct dom_sid *sid) 3961 { 3962 /* strategy: 3963 - find DN of record with the DSA GUID in the 3964 configuration partition (objectGUID) 3965 - remove "NTDS Settings" component from DN 3966 - do a base search on that DN for serverReference with 3967 extended-dn enabled 3968 - extract objectSid from resulting serverReference 3969 attribute 3970 - check this sid matches the sid argument 3971 */ 3972 struct ldb_dn *config_dn; 3973 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 2495 3974 struct ldb_message *msg; 2496 struct dsdb_control_current_partition *p_ctrl; 2497 int ret; 2498 2499 msg = ldb_msg_new(ldb); 2500 if (msg == NULL) { 2501 return LDB_ERR_OPERATIONS_ERROR; 2502 } 2503 2504 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED"); 2505 if (msg->dn == NULL) { 2506 talloc_free(msg); 2507 return LDB_ERR_OPERATIONS_ERROR; 2508 } 2509 2510 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN); 2511 if (ret != LDB_SUCCESS) { 2512 talloc_free(msg); 2513 return ret; 2514 } 2515 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE; 2516 2517 2518 p_ctrl = talloc(msg, struct dsdb_control_current_partition); 2519 if (p_ctrl == NULL) { 2520 talloc_free(msg); 2521 return LDB_ERR_OPERATIONS_ERROR; 2522 } 2523 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION; 2524 p_ctrl->dn = dn; 2525 2526 ret = ldb_build_mod_req(&req, ldb, msg, 2527 msg, 2528 NULL, 2529 NULL, ldb_op_default_callback, 2530 NULL); 2531 again: 2532 if (ret != LDB_SUCCESS) { 2533 talloc_free(msg); 2534 return ret; 2535 } 2536 2537 ret = ldb_request_add_control(req, 2538 DSDB_CONTROL_CURRENT_PARTITION_OID, 2539 false, p_ctrl); 2540 if (ret != LDB_SUCCESS) { 2541 talloc_free(msg); 2542 return ret; 2543 } 2544 2545 /* Run the new request */ 2546 ret = ldb_request(ldb, req); 2547 2548 if (ret == LDB_SUCCESS) { 2549 ret = ldb_wait(req->handle, LDB_WAIT_ALL); 2550 } 2551 if (ret == LDB_ERR_NO_SUCH_OBJECT) { 2552 ret = ldb_build_add_req(&req, ldb, msg, 2553 msg, 2554 NULL, 2555 NULL, ldb_op_default_callback, 2556 NULL); 2557 goto again; 2558 } 2559 2560 talloc_free(msg); 2561 2562 return ret; 2563 } 2564 2565 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1, 2566 const struct drsuapi_DsReplicaCursor2 *c2) 2567 { 2568 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id); 2569 } 3975 const char *attrs1[] = { NULL }; 3976 const char *attrs2[] = { "serverReference", NULL }; 3977 int ret; 3978 struct ldb_dn *dn, *account_dn; 3979 struct dom_sid sid2; 3980 NTSTATUS status; 3981 3982 config_dn = ldb_get_config_basedn(ldb); 3983 3984 ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE, 3985 attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid)); 3986 if (ret != LDB_SUCCESS) { 3987 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n", 3988 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid))); 3989 talloc_free(tmp_ctx); 3990 return ldb_operr(ldb); 3991 } 3992 dn = msg->dn; 3993 3994 if (!ldb_dn_remove_child_components(dn, 1)) { 3995 talloc_free(tmp_ctx); 3996 return ldb_operr(ldb); 3997 } 3998 3999 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, 4000 attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN, 4001 "(objectClass=server)"); 4002 if (ret != LDB_SUCCESS) { 4003 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n", 4004 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid))); 4005 talloc_free(tmp_ctx); 4006 return ldb_operr(ldb); 4007 } 4008 4009 account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference"); 4010 if (account_dn == NULL) { 4011 DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n", 4012 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid))); 4013 talloc_free(tmp_ctx); 4014 return ldb_operr(ldb); 4015 } 4016 4017 status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID"); 4018 if (!NT_STATUS_IS_OK(status)) { 4019 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n", 4020 GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid))); 4021 talloc_free(tmp_ctx); 4022 return ldb_operr(ldb); 4023 } 4024 4025 if (!dom_sid_equal(sid, &sid2)) { 4026 /* someone is trying to spoof another account */ 4027 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n", 4028 GUID_string(tmp_ctx, dsa_guid), 4029 dom_sid_string(tmp_ctx, sid), 4030 dom_sid_string(tmp_ctx, &sid2))); 4031 talloc_free(tmp_ctx); 4032 return ldb_operr(ldb); 4033 } 4034 4035 talloc_free(tmp_ctx); 4036 return LDB_SUCCESS; 4037 } 4038 4039 static const char * const secret_attributes[] = { 4040 DSDB_SECRET_ATTRIBUTES, 4041 NULL 4042 }; 4043 4044 /* 4045 check if the attribute belongs to the RODC filtered attribute set 4046 Note that attributes that are in the filtered attribute set are the 4047 ones that _are_ always sent to a RODC 4048 */ 4049 bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa) 4050 { 4051 /* they never get secret attributes */ 4052 if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) { 4053 return false; 4054 } 4055 4056 /* they do get non-secret critical attributes */ 4057 if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) { 4058 return true; 4059 } 4060 4061 /* they do get non-secret attributes marked as being in the FAS */ 4062 if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) { 4063 return true; 4064 } 4065 4066 /* other attributes are denied */ 4067 return false; 4068 } 4069 4070 /* return fsmo role dn and role owner dn for a particular role*/ 4071 WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx, 4072 struct ldb_context *ldb, 4073 uint32_t role, 4074 struct ldb_dn **fsmo_role_dn, 4075 struct ldb_dn **role_owner_dn) 4076 { 4077 int ret; 4078 switch (role) { 4079 case DREPL_NAMING_MASTER: 4080 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx); 4081 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn); 4082 if (ret != LDB_SUCCESS) { 4083 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s", 4084 ldb_errstring(ldb))); 4085 talloc_free(tmp_ctx); 4086 return WERR_DS_DRA_INTERNAL_ERROR; 4087 } 4088 break; 4089 case DREPL_INFRASTRUCTURE_MASTER: 4090 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx); 4091 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn); 4092 if (ret != LDB_SUCCESS) { 4093 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s", 4094 ldb_errstring(ldb))); 4095 talloc_free(tmp_ctx); 4096 return WERR_DS_DRA_INTERNAL_ERROR; 4097 } 4098 break; 4099 case DREPL_RID_MASTER: 4100 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn); 4101 if (ret != LDB_SUCCESS) { 4102 DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb))); 4103 talloc_free(tmp_ctx); 4104 return WERR_DS_DRA_INTERNAL_ERROR; 4105 } 4106 4107 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn); 4108 if (ret != LDB_SUCCESS) { 4109 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s", 4110 ldb_errstring(ldb))); 4111 talloc_free(tmp_ctx); 4112 return WERR_DS_DRA_INTERNAL_ERROR; 4113 } 4114 break; 4115 case DREPL_SCHEMA_MASTER: 4116 *fsmo_role_dn = ldb_get_schema_basedn(ldb); 4117 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn); 4118 if (ret != LDB_SUCCESS) { 4119 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s", 4120 ldb_errstring(ldb))); 4121 talloc_free(tmp_ctx); 4122 return WERR_DS_DRA_INTERNAL_ERROR; 4123 } 4124 break; 4125 case DREPL_PDC_MASTER: 4126 *fsmo_role_dn = ldb_get_default_basedn(ldb); 4127 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn); 4128 if (ret != LDB_SUCCESS) { 4129 DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s", 4130 ldb_errstring(ldb))); 4131 talloc_free(tmp_ctx); 4132 return WERR_DS_DRA_INTERNAL_ERROR; 4133 } 4134 break; 4135 default: 4136 return WERR_DS_DRA_INTERNAL_ERROR; 4137 } 4138 return WERR_OK; 4139 } 4140 4141 const char *samdb_dn_to_dnshostname(struct ldb_context *ldb, 4142 TALLOC_CTX *mem_ctx, 4143 struct ldb_dn *server_dn) 4144 { 4145 int ldb_ret; 4146 struct ldb_result *res = NULL; 4147 const char * const attrs[] = { "dNSHostName", NULL}; 4148 4149 ldb_ret = ldb_search(ldb, mem_ctx, &res, 4150 server_dn, 4151 LDB_SCOPE_BASE, 4152 attrs, NULL); 4153 if (ldb_ret != LDB_SUCCESS) { 4154 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s", 4155 ldb_dn_get_linearized(server_dn), ldb_errstring(ldb))); 4156 return NULL; 4157 } 4158 4159 return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL); 4160 } 4161 4162 /* 4163 returns true if an attribute is in the filter, 4164 false otherwise, provided that attribute value is provided with the expression 4165 */ 4166 bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree, 4167 const char *attr) 4168 { 4169 unsigned int i; 4170 switch (tree->operation) { 4171 case LDB_OP_AND: 4172 case LDB_OP_OR: 4173 for (i=0;i<tree->u.list.num_elements;i++) { 4174 if (dsdb_attr_in_parse_tree(tree->u.list.elements[i], 4175 attr)) 4176 return true; 4177 } 4178 return false; 4179 case LDB_OP_NOT: 4180 return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr); 4181 case LDB_OP_EQUALITY: 4182 case LDB_OP_GREATER: 4183 case LDB_OP_LESS: 4184 case LDB_OP_APPROX: 4185 if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) { 4186 return true; 4187 } 4188 return false; 4189 case LDB_OP_SUBSTRING: 4190 if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) { 4191 return true; 4192 } 4193 return false; 4194 case LDB_OP_PRESENT: 4195 /* (attrname=*) is not filtered out */ 4196 return false; 4197 case LDB_OP_EXTENDED: 4198 if (tree->u.extended.attr && 4199 ldb_attr_cmp(tree->u.extended.attr, attr) == 0) { 4200 return true; 4201 } 4202 return false; 4203 } 4204 return false; 4205 } 4206 4207 bool is_attr_in_list(const char * const * attrs, const char *attr) 4208 { 4209 unsigned int i; 4210 4211 for (i = 0; attrs[i]; i++) { 4212 if (ldb_attr_cmp(attrs[i], attr) == 0) 4213 return true; 4214 } 4215 4216 return false; 4217 } 4218
Note:
See TracChangeset
for help on using the changeset viewer.