1/* 2 Unix SMB/CIFS implementation. 3 Samba utility functions 4 5 Copyright (C) Andrew Tridgell 2004 6 Copyright (C) Volker Lendecke 2004 7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 8 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program. If not, see <http://www.gnu.org/licenses/>. 22*/ 23 24#include "includes.h" 25#include "events/events.h" 26#include "ldb.h" 27#include "ldb_errors.h" 28#include "../lib/util/util_ldb.h" 29#include "../lib/crypto/crypto.h" 30#include "dsdb/samdb/samdb.h" 31#include "libcli/security/security.h" 32#include "librpc/gen_ndr/ndr_security.h" 33#include "librpc/gen_ndr/ndr_misc.h" 34#include "../libds/common/flags.h" 35#include "dsdb/common/proto.h" 36#include "libcli/ldap/ldap_ndr.h" 37#include "param/param.h" 38#include "libcli/auth/libcli_auth.h" 39#include "librpc/gen_ndr/ndr_drsblobs.h" 40 41/* 42 search the sam for the specified attributes in a specific domain, filter on 43 objectSid being in domain_sid. 44*/ 45int samdb_search_domain(struct ldb_context *sam_ldb, 46 TALLOC_CTX *mem_ctx, 47 struct ldb_dn *basedn, 48 struct ldb_message ***res, 49 const char * const *attrs, 50 const struct dom_sid *domain_sid, 51 const char *format, ...) _PRINTF_ATTRIBUTE(7,8) 52{ 53 va_list ap; 54 int i, count; 55 56 va_start(ap, format); 57 count = gendb_search_v(sam_ldb, mem_ctx, basedn, 58 res, attrs, format, ap); 59 va_end(ap); 60 61 i=0; 62 63 while (i<count) { 64 struct dom_sid *entry_sid; 65 66 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid"); 67 68 if ((entry_sid == NULL) || 69 (!dom_sid_in_domain(domain_sid, entry_sid))) { 70 /* Delete that entry from the result set */ 71 (*res)[i] = (*res)[count-1]; 72 count -= 1; 73 talloc_free(entry_sid); 74 continue; 75 } 76 talloc_free(entry_sid); 77 i += 1; 78 } 79 80 return count; 81} 82 83/* 84 search the sam for a single string attribute in exactly 1 record 85*/ 86const char *samdb_search_string_v(struct ldb_context *sam_ldb, 87 TALLOC_CTX *mem_ctx, 88 struct ldb_dn *basedn, 89 const char *attr_name, 90 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0) 91{ 92 int count; 93 const char *attrs[2] = { NULL, NULL }; 94 struct ldb_message **res = NULL; 95 96 attrs[0] = attr_name; 97 98 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); 99 if (count > 1) { 100 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 101 attr_name, format, count)); 102 } 103 if (count != 1) { 104 talloc_free(res); 105 return NULL; 106 } 107 108 return samdb_result_string(res[0], attr_name, NULL); 109} 110 111/* 112 search the sam for a single string attribute in exactly 1 record 113*/ 114const char *samdb_search_string(struct ldb_context *sam_ldb, 115 TALLOC_CTX *mem_ctx, 116 struct ldb_dn *basedn, 117 const char *attr_name, 118 const char *format, ...) _PRINTF_ATTRIBUTE(5,6) 119{ 120 va_list ap; 121 const char *str; 122 123 va_start(ap, format); 124 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap); 125 va_end(ap); 126 127 return str; 128} 129 130struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb, 131 TALLOC_CTX *mem_ctx, 132 struct ldb_dn *basedn, 133 const char *format, ...) _PRINTF_ATTRIBUTE(4,5) 134{ 135 va_list ap; 136 struct ldb_dn *ret; 137 struct ldb_message **res = NULL; 138 int count; 139 140 va_start(ap, format); 141 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap); 142 va_end(ap); 143 144 if (count != 1) return NULL; 145 146 ret = talloc_steal(mem_ctx, res[0]->dn); 147 talloc_free(res); 148 149 return ret; 150} 151 152/* 153 search the sam for a dom_sid attribute in exactly 1 record 154*/ 155struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb, 156 TALLOC_CTX *mem_ctx, 157 struct ldb_dn *basedn, 158 const char *attr_name, 159 const char *format, ...) _PRINTF_ATTRIBUTE(5,6) 160{ 161 va_list ap; 162 int count; 163 struct ldb_message **res; 164 const char *attrs[2] = { NULL, NULL }; 165 struct dom_sid *sid; 166 167 attrs[0] = attr_name; 168 169 va_start(ap, format); 170 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); 171 va_end(ap); 172 if (count > 1) { 173 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 174 attr_name, format, count)); 175 } 176 if (count != 1) { 177 talloc_free(res); 178 return NULL; 179 } 180 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name); 181 talloc_free(res); 182 return sid; 183} 184 185/* 186 return the count of the number of records in the sam matching the query 187*/ 188int samdb_search_count(struct ldb_context *sam_ldb, 189 TALLOC_CTX *mem_ctx, 190 struct ldb_dn *basedn, 191 const char *format, ...) _PRINTF_ATTRIBUTE(4,5) 192{ 193 va_list ap; 194 struct ldb_message **res; 195 const char * const attrs[] = { NULL }; 196 int ret; 197 198 va_start(ap, format); 199 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); 200 va_end(ap); 201 202 return ret; 203} 204 205 206/* 207 search the sam for a single integer attribute in exactly 1 record 208*/ 209uint_t samdb_search_uint(struct ldb_context *sam_ldb, 210 TALLOC_CTX *mem_ctx, 211 uint_t default_value, 212 struct ldb_dn *basedn, 213 const char *attr_name, 214 const char *format, ...) _PRINTF_ATTRIBUTE(6,7) 215{ 216 va_list ap; 217 int count; 218 struct ldb_message **res; 219 const char *attrs[2] = { NULL, NULL }; 220 221 attrs[0] = attr_name; 222 223 va_start(ap, format); 224 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); 225 va_end(ap); 226 227 if (count != 1) { 228 return default_value; 229 } 230 231 return samdb_result_uint(res[0], attr_name, default_value); 232} 233 234/* 235 search the sam for a single signed 64 bit integer attribute in exactly 1 record 236*/ 237int64_t samdb_search_int64(struct ldb_context *sam_ldb, 238 TALLOC_CTX *mem_ctx, 239 int64_t default_value, 240 struct ldb_dn *basedn, 241 const char *attr_name, 242 const char *format, ...) _PRINTF_ATTRIBUTE(6,7) 243{ 244 va_list ap; 245 int count; 246 struct ldb_message **res; 247 const char *attrs[2] = { NULL, NULL }; 248 249 attrs[0] = attr_name; 250 251 va_start(ap, format); 252 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); 253 va_end(ap); 254 255 if (count != 1) { 256 return default_value; 257 } 258 259 return samdb_result_int64(res[0], attr_name, default_value); 260} 261 262/* 263 search the sam for multipe records each giving a single string attribute 264 return the number of matches, or -1 on error 265*/ 266int samdb_search_string_multiple(struct ldb_context *sam_ldb, 267 TALLOC_CTX *mem_ctx, 268 struct ldb_dn *basedn, 269 const char ***strs, 270 const char *attr_name, 271 const char *format, ...) _PRINTF_ATTRIBUTE(6,7) 272{ 273 va_list ap; 274 int count, i; 275 const char *attrs[2] = { NULL, NULL }; 276 struct ldb_message **res = NULL; 277 278 attrs[0] = attr_name; 279 280 va_start(ap, format); 281 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); 282 va_end(ap); 283 284 if (count <= 0) { 285 return count; 286 } 287 288 /* make sure its single valued */ 289 for (i=0;i<count;i++) { 290 if (res[i]->num_elements != 1) { 291 DEBUG(1,("samdb: search for %s %s not single valued\n", 292 attr_name, format)); 293 talloc_free(res); 294 return -1; 295 } 296 } 297 298 *strs = talloc_array(mem_ctx, const char *, count+1); 299 if (! *strs) { 300 talloc_free(res); 301 return -1; 302 } 303 304 for (i=0;i<count;i++) { 305 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL); 306 } 307 (*strs)[count] = NULL; 308 309 return count; 310} 311 312/* 313 pull a uint from a result set. 314*/ 315uint_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*/ 323int64_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*/ 331const 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} 336 337struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 338 const char *attr, struct ldb_dn *default_value) 339{ 340 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr); 341 if (!ret_dn) { 342 return default_value; 343 } 344 return ret_dn; 345} 346 347/* 348 pull a rid from a objectSid in a result set. 349*/ 350uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 351 const char *attr, uint32_t default_value) 352{ 353 struct dom_sid *sid; 354 uint32_t rid; 355 356 sid = samdb_result_dom_sid(mem_ctx, msg, attr); 357 if (sid == NULL) { 358 return default_value; 359 } 360 rid = sid->sub_auths[sid->num_auths-1]; 361 talloc_free(sid); 362 return rid; 363} 364 365/* 366 pull a dom_sid structure from a objectSid in a result set. 367*/ 368struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 369 const char *attr) 370{ 371 const struct ldb_val *v; 372 struct dom_sid *sid; 373 enum ndr_err_code ndr_err; 374 v = ldb_msg_find_ldb_val(msg, attr); 375 if (v == NULL) { 376 return NULL; 377 } 378 sid = talloc(mem_ctx, struct dom_sid); 379 if (sid == NULL) { 380 return NULL; 381 } 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)) { 385 talloc_free(sid); 386 return NULL; 387 } 388 return sid; 389} 390 391/* 392 pull a guid structure from a objectGUID in a result set. 393*/ 394struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr) 395{ 396 const struct ldb_val *v; 397 enum ndr_err_code ndr_err; 398 struct GUID guid; 399 TALLOC_CTX *mem_ctx; 400 401 ZERO_STRUCT(guid); 402 403 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; 413 } 414 415 return guid; 416} 417 418/* 419 pull a sid prefix from a objectSid in a result set. 420 this is used to find the domain sid for a user 421*/ 422struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 423 const char *attr) 424{ 425 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr); 426 if (!sid || sid->num_auths < 1) return NULL; 427 sid->num_auths--; 428 return sid; 429} 430 431/* 432 pull a NTTIME in a result set. 433*/ 434NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value) 435{ 436 return ldb_msg_find_attr_as_uint64(msg, attr, default_value); 437} 438 439/* 440 * Windows stores 0 for lastLogoff. 441 * But when a MS DC return the lastLogoff (as Logoff Time) 442 * it returns 0x7FFFFFFFFFFFFFFF, not returning this value in this case 443 * cause windows 2008 and newer version to fail for SMB requests 444 */ 445NTTIME samdb_result_last_logoff(struct ldb_message *msg) 446{ 447 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0); 448 449 if (ret == 0) 450 ret = 0x7FFFFFFFFFFFFFFFULL; 451 452 return ret; 453} 454 455/* 456 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to 457 * indicate an account doesn't expire. 458 * 459 * When Windows initially creates an account, it sets 460 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However, 461 * when changing from an account having a specific expiration date to 462 * that account never expiring, it sets accountExpires = 0. 463 * 464 * Consolidate that logic here to allow clearer logic for account expiry in 465 * the rest of the code. 466 */ 467NTTIME samdb_result_account_expires(struct ldb_message *msg) 468{ 469 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires", 470 0); 471 472 if (ret == 0) 473 ret = 0x7FFFFFFFFFFFFFFFULL; 474 475 return ret; 476} 477 478/* 479 pull a uint64_t from a result set. 480*/ 481uint64_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 487/* 488 construct the allow_password_change field from the PwdLastSet attribute and the 489 domain password settings 490*/ 491NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 492 TALLOC_CTX *mem_ctx, 493 struct ldb_dn *domain_dn, 494 struct ldb_message *msg, 495 const char *attr) 496{ 497 uint64_t attr_time = samdb_result_uint64(msg, attr, 0); 498 int64_t minPwdAge; 499 500 if (attr_time == 0) { 501 return 0; 502 } 503 504 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL); 505 506 /* yes, this is a -= not a += as minPwdAge is stored as the negative 507 of the number of 100-nano-seconds */ 508 attr_time -= minPwdAge; 509 510 return attr_time; 511} 512 513/* 514 construct the force_password_change field from the PwdLastSet 515 attribute, the userAccountControl and the domain password settings 516*/ 517NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 518 TALLOC_CTX *mem_ctx, 519 struct ldb_dn *domain_dn, 520 struct ldb_message *msg) 521{ 522 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0); 523 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0); 524 int64_t maxPwdAge; 525 526 /* Machine accounts don't expire, and there is a flag for 'no expiry' */ 527 if (!(userAccountControl & UF_NORMAL_ACCOUNT) 528 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) { 529 return 0x7FFFFFFFFFFFFFFFULL; 530 } 531 532 if (attr_time == 0) { 533 return 0; 534 } 535 536 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL); 537 if (maxPwdAge == 0) { 538 return 0x7FFFFFFFFFFFFFFFULL; 539 } else { 540 attr_time -= maxPwdAge; 541 } 542 543 return attr_time; 544} 545 546/* 547 pull a samr_Password structutre from a result set. 548*/ 549struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr) 550{ 551 struct samr_Password *hash = NULL; 552 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); 553 if (val && (val->length >= sizeof(hash->hash))) { 554 hash = talloc(mem_ctx, struct samr_Password); 555 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash))); 556 } 557 return hash; 558} 559 560/* 561 pull an array of samr_Password structutres from a result set. 562*/ 563uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 564 const char *attr, struct samr_Password **hashes) 565{ 566 uint_t count = 0; 567 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); 568 int i; 569 570 *hashes = NULL; 571 if (!val) { 572 return 0; 573 } 574 count = val->length / 16; 575 if (count == 0) { 576 return 0; 577 } 578 579 *hashes = talloc_array(mem_ctx, struct samr_Password, count); 580 if (! *hashes) { 581 return 0; 582 } 583 584 for (i=0;i<count;i++) { 585 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16); 586 } 587 588 return count; 589} 590 591NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 592 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 593{ 594 struct samr_Password *lmPwdHash, *ntPwdHash; 595 if (nt_pwd) { 596 int num_nt; 597 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash); 598 if (num_nt == 0) { 599 *nt_pwd = NULL; 600 } else if (num_nt > 1) { 601 return NT_STATUS_INTERNAL_DB_CORRUPTION; 602 } else { 603 *nt_pwd = &ntPwdHash[0]; 604 } 605 } 606 if (lm_pwd) { 607 /* Ensure that if we have turned off LM 608 * authentication, that we never use the LM hash, even 609 * if we store it */ 610 if (lp_lanman_auth(lp_ctx)) { 611 int num_lm; 612 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash); 613 if (num_lm == 0) { 614 *lm_pwd = NULL; 615 } else if (num_lm > 1) { 616 return NT_STATUS_INTERNAL_DB_CORRUPTION; 617 } else { 618 *lm_pwd = &lmPwdHash[0]; 619 } 620 } else { 621 *lm_pwd = NULL; 622 } 623 } 624 return NT_STATUS_OK; 625} 626 627/* 628 pull a samr_LogonHours structutre from a result set. 629*/ 630struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr) 631{ 632 struct samr_LogonHours hours; 633 const int units_per_week = 168; 634 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); 635 ZERO_STRUCT(hours); 636 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week); 637 if (!hours.bits) { 638 return hours; 639 } 640 hours.units_per_week = units_per_week; 641 memset(hours.bits, 0xFF, units_per_week); 642 if (val) { 643 memcpy(hours.bits, val->data, MIN(val->length, units_per_week)); 644 } 645 return hours; 646} 647 648/* 649 pull a set of account_flags from a result set. 650 651 This requires that the attributes: 652 pwdLastSet 653 userAccountControl 654 be included in 'msg' 655*/ 656uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 657 struct ldb_message *msg, struct ldb_dn *domain_dn) 658{ 659 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); 660 uint32_t acct_flags = ds_uf2acb(userAccountControl); 661 NTTIME must_change_time; 662 NTTIME now; 663 664 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 665 domain_dn, msg); 666 667 /* Test account expire time */ 668 unix_to_nt_time(&now, time(NULL)); 669 /* check for expired password */ 670 if (must_change_time < now) { 671 acct_flags |= ACB_PW_EXPIRED; 672 } 673 return acct_flags; 674} 675 676struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx, 677 struct ldb_message *msg, 678 const char *attr) 679{ 680 struct lsa_BinaryString s; 681 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); 682 683 ZERO_STRUCT(s); 684 685 if (!val) { 686 return s; 687 } 688 689 s.array = talloc_array(mem_ctx, uint16_t, val->length/2); 690 if (!s.array) { 691 return s; 692 } 693 s.length = s.size = val->length/2; 694 memcpy(s.array, val->data, val->length); 695 696 return s; 697} 698 699/* Find an attribute, with a particular value */ 700 701/* The current callers of this function expect a very specific 702 * behaviour: In particular, objectClass subclass equivilance is not 703 * wanted. This means that we should not lookup the schema for the 704 * comparison function */ 705struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 706 const struct ldb_message *msg, 707 const char *name, const char *value) 708{ 709 int i; 710 struct ldb_message_element *el = ldb_msg_find_element(msg, name); 711 712 if (!el) { 713 return NULL; 714 } 715 716 for (i=0;i<el->num_values;i++) { 717 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) { 718 return el; 719 } 720 } 721 722 return NULL; 723} 724 725int 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 733int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value) 734{ 735 struct ldb_message_element *el; 736 737 el = ldb_msg_find_element(msg, name); 738 if (el) { 739 return LDB_SUCCESS; 740 } 741 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*/ 750int 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); 759} 760 761/* 762 add a dom_sid element to a message 763*/ 764int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 765 const char *attr_name, struct dom_sid *sid) 766{ 767 struct ldb_val v; 768 enum ndr_err_code ndr_err; 769 770 ndr_err = ndr_push_struct_blob(&v, mem_ctx, 771 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")), 772 sid, 773 (ndr_push_flags_fn_t)ndr_push_dom_sid); 774 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 775 return -1; 776 } 777 return ldb_msg_add_value(msg, attr_name, &v, NULL); 778} 779 780 781/* 782 add a delete element operation to a message 783*/ 784int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 785 const char *attr_name) 786{ 787 /* we use an empty replace rather than a delete, as it allows for 788 samdb_replace() to be used everywhere */ 789 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL); 790} 791 792/* 793 add a add attribute value to a message 794*/ 795int 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) 797{ 798 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; 804 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*/ 820int 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) 822{ 823 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; 829 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; 840} 841 842/* 843 add a int element to a message 844*/ 845int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 846 const char *attr_name, int v) 847{ 848 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*/ 855int 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); 860} 861 862/* 863 add a (signed) int64_t element to a message 864*/ 865int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 866 const char *attr_name, int64_t v) 867{ 868 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*/ 875int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 876 const char *attr_name, uint64_t v) 877{ 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); 880} 881 882/* 883 add a samr_Password element to a message 884*/ 885int 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) 887{ 888 struct ldb_val val; 889 val.data = talloc_memdup(mem_ctx, hash->hash, 16); 890 if (!val.data) { 891 return -1; 892 } 893 val.length = 16; 894 return ldb_msg_add_value(msg, attr_name, &val, NULL); 895} 896 897/* 898 add a samr_Password array to a message 899*/ 900int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 901 const char *attr_name, struct samr_Password *hashes, uint_t count) 902{ 903 struct ldb_val val; 904 int i; 905 val.data = talloc_array_size(mem_ctx, 16, count); 906 val.length = count*16; 907 if (!val.data) { 908 return -1; 909 } 910 for (i=0;i<count;i++) { 911 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16); 912 } 913 return ldb_msg_add_value(msg, attr_name, &val, NULL); 914} 915 916/* 917 add a acct_flags element to a message 918*/ 919int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 920 const char *attr_name, uint32_t v) 921{ 922 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v)); 923} 924 925/* 926 add a logon_hours element to a message 927*/ 928int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 929 const char *attr_name, struct samr_LogonHours *hours) 930{ 931 struct ldb_val val; 932 val.length = hours->units_per_week / 8; 933 val.data = hours->bits; 934 return ldb_msg_add_value(msg, attr_name, &val, NULL); 935} 936 937/* 938 add a parameters element to a message 939*/ 940int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 941 const char *attr_name, struct lsa_BinaryString *parameters) 942{ 943 struct ldb_val val; 944 val.length = parameters->length * 2; 945 val.data = (uint8_t *)parameters->array; 946 return ldb_msg_add_value(msg, attr_name, &val, NULL); 947} 948/* 949 add a general value element to a message 950*/ 951int 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} 956 957/* 958 sets a general value element to a message 959*/ 960int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 961 const char *attr_name, const struct ldb_val *val) 962{ 963 struct ldb_message_element *el; 964 965 el = ldb_msg_find_element(msg, attr_name); 966 if (el) { 967 el->num_values = 0; 968 } 969 return ldb_msg_add_value(msg, attr_name, val, NULL); 970} 971 972/* 973 set a string element in a message 974*/ 975int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, 976 const char *attr_name, const char *str) 977{ 978 struct ldb_message_element *el; 979 980 el = ldb_msg_find_element(msg, attr_name); 981 if (el) { 982 el->num_values = 0; 983 } 984 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str); 985} 986 987/* 988 replace elements in a record 989*/ 990int 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); 1001} 1002 1003/* 1004 return a default security descriptor 1005*/ 1006struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx) 1007{ 1008 struct security_descriptor *sd; 1009 1010 sd = security_descriptor_initialise(mem_ctx); 1011 1012 return sd; 1013} 1014 1015struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 1016{ 1017 return ldb_get_default_basedn(sam_ctx); 1018} 1019 1020struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 1021{ 1022 return ldb_get_config_basedn(sam_ctx); 1023} 1024 1025struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 1026{ 1027 return ldb_get_schema_basedn(sam_ctx); 1028} 1029 1030struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 1031{ 1032 return ldb_get_root_basedn(sam_ctx); 1033} 1034 1035struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 1036{ 1037 struct ldb_dn *new_dn; 1038 1039 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx)); 1040 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) { 1041 talloc_free(new_dn); 1042 return NULL; 1043 } 1044 return new_dn; 1045} 1046 1047struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) 1048{ 1049 struct ldb_dn *new_dn; 1050 1051 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx)); 1052 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) { 1053 talloc_free(new_dn); 1054 return NULL; 1055 } 1056 return new_dn; 1057} 1058 1059/* 1060 work out the domain sid for the current open ldb 1061*/ 1062const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb) 1063{ 1064 TALLOC_CTX *tmp_ctx; 1065 const struct dom_sid *domain_sid; 1066 const char *attrs[] = { 1067 "objectSid", 1068 NULL 1069 }; 1070 struct ldb_result *res; 1071 int ret; 1072 1073 /* see if we have a cached copy */ 1074 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid"); 1075 if (domain_sid) { 1076 return domain_sid; 1077 } 1078 1079 tmp_ctx = talloc_new(ldb); 1080 if (tmp_ctx == NULL) { 1081 goto failed; 1082 } 1083 1084 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*"); 1085 1086 if (ret != LDB_SUCCESS) { 1087 goto failed; 1088 } 1089 1090 if (res->count != 1) { 1091 goto failed; 1092 } 1093 1094 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid"); 1095 if (domain_sid == NULL) { 1096 goto failed; 1097 } 1098 1099 /* cache the domain_sid in the ldb */ 1100 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) { 1101 goto failed; 1102 } 1103 1104 talloc_steal(ldb, domain_sid); 1105 talloc_free(tmp_ctx); 1106 1107 return domain_sid; 1108 1109failed: 1110 DEBUG(1,("Failed to find domain_sid for open ldb\n")); 1111 talloc_free(tmp_ctx); 1112 return NULL; 1113} 1114 1115bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in) 1116{ 1117 TALLOC_CTX *tmp_ctx; 1118 struct dom_sid *dom_sid_new; 1119 struct dom_sid *dom_sid_old; 1120 1121 /* see if we have a cached copy */ 1122 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 1123 "cache.domain_sid"), struct dom_sid); 1124 1125 tmp_ctx = talloc_new(ldb); 1126 if (tmp_ctx == NULL) { 1127 goto failed; 1128 } 1129 1130 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in); 1131 if (!dom_sid_new) { 1132 goto failed; 1133 } 1134 1135 /* cache the domain_sid in the ldb */ 1136 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) { 1137 goto failed; 1138 } 1139 1140 talloc_steal(ldb, dom_sid_new); 1141 talloc_free(tmp_ctx); 1142 talloc_free(dom_sid_old); 1143 1144 return true; 1145 1146failed: 1147 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n")); 1148 talloc_free(tmp_ctx); 1149 return false; 1150} 1151 1152/* Obtain the short name of the flexible single master operator 1153 * (FSMO), such as the PDC Emulator */ 1154const 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; 1172} 1173 1174/* 1175 work out the ntds settings dn for the current open ldb 1176*/ 1177struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb) 1178{ 1179 TALLOC_CTX *tmp_ctx; 1180 const char *root_attrs[] = { "dsServiceName", NULL }; 1181 int ret; 1182 struct ldb_result *root_res; 1183 struct ldb_dn *settings_dn; 1184 1185 /* see if we have a cached copy */ 1186 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn"); 1187 if (settings_dn) { 1188 return settings_dn; 1189 } 1190 1191 tmp_ctx = talloc_new(ldb); 1192 if (tmp_ctx == NULL) { 1193 goto failed; 1194 } 1195 1196 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL); 1197 if (ret) { 1198 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 1199 ldb_errstring(ldb))); 1200 goto failed; 1201 } 1202 1203 if (root_res->count != 1) { 1204 goto failed; 1205 } 1206 1207 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName"); 1208 1209 /* cache the domain_sid in the ldb */ 1210 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) { 1211 goto failed; 1212 } 1213 1214 talloc_steal(ldb, settings_dn); 1215 talloc_free(tmp_ctx); 1216 1217 return settings_dn; 1218 1219failed: 1220 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n")); 1221 talloc_free(tmp_ctx); 1222 return NULL; 1223} 1224 1225/* 1226 work out the ntds settings invocationId for the current open ldb 1227*/ 1228const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb) 1229{ 1230 TALLOC_CTX *tmp_ctx; 1231 const char *attrs[] = { "invocationId", NULL }; 1232 int ret; 1233 struct ldb_result *res; 1234 struct GUID *invocation_id; 1235 1236 /* see if we have a cached copy */ 1237 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id"); 1238 if (invocation_id) { 1239 return invocation_id; 1240 } 1241 1242 tmp_ctx = talloc_new(ldb); 1243 if (tmp_ctx == NULL) { 1244 goto failed; 1245 } 1246 1247 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); 1248 if (ret) { 1249 goto failed; 1250 } 1251 1252 if (res->count != 1) { 1253 goto failed; 1254 } 1255 1256 invocation_id = talloc(tmp_ctx, struct GUID); 1257 if (!invocation_id) { 1258 goto failed; 1259 } 1260 1261 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId"); 1262 1263 /* cache the domain_sid in the ldb */ 1264 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) { 1265 goto failed; 1266 } 1267 1268 talloc_steal(ldb, invocation_id); 1269 talloc_free(tmp_ctx); 1270 1271 return invocation_id; 1272 1273failed: 1274 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n")); 1275 talloc_free(tmp_ctx); 1276 return NULL; 1277} 1278 1279bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in) 1280{ 1281 TALLOC_CTX *tmp_ctx; 1282 struct GUID *invocation_id_new; 1283 struct GUID *invocation_id_old; 1284 1285 /* see if we have a cached copy */ 1286 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 1287 "cache.invocation_id"); 1288 1289 tmp_ctx = talloc_new(ldb); 1290 if (tmp_ctx == NULL) { 1291 goto failed; 1292 } 1293 1294 invocation_id_new = talloc(tmp_ctx, struct GUID); 1295 if (!invocation_id_new) { 1296 goto failed; 1297 } 1298 1299 *invocation_id_new = *invocation_id_in; 1300 1301 /* cache the domain_sid in the ldb */ 1302 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) { 1303 goto failed; 1304 } 1305 1306 talloc_steal(ldb, invocation_id_new); 1307 talloc_free(tmp_ctx); 1308 talloc_free(invocation_id_old); 1309 1310 return true; 1311 1312failed: 1313 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n")); 1314 talloc_free(tmp_ctx); 1315 return false; 1316} 1317 1318/* 1319 work out the ntds settings objectGUID for the current open ldb 1320*/ 1321const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb) 1322{ 1323 TALLOC_CTX *tmp_ctx; 1324 const char *attrs[] = { "objectGUID", NULL }; 1325 int ret; 1326 struct ldb_result *res; 1327 struct GUID *ntds_guid; 1328 1329 /* see if we have a cached copy */ 1330 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); 1331 if (ntds_guid) { 1332 return ntds_guid; 1333 } 1334 1335 tmp_ctx = talloc_new(ldb); 1336 if (tmp_ctx == NULL) { 1337 goto failed; 1338 } 1339 1340 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); 1341 if (ret) { 1342 goto failed; 1343 } 1344 1345 if (res->count != 1) { 1346 goto failed; 1347 } 1348 1349 ntds_guid = talloc(tmp_ctx, struct GUID); 1350 if (!ntds_guid) { 1351 goto failed; 1352 } 1353 1354 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID"); 1355 1356 /* cache the domain_sid in the ldb */ 1357 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) { 1358 goto failed; 1359 } 1360 1361 talloc_steal(ldb, ntds_guid); 1362 talloc_free(tmp_ctx); 1363 1364 return ntds_guid; 1365 1366failed: 1367 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n")); 1368 talloc_free(tmp_ctx); 1369 return NULL; 1370} 1371 1372bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in) 1373{ 1374 TALLOC_CTX *tmp_ctx; 1375 struct GUID *ntds_guid_new; 1376 struct GUID *ntds_guid_old; 1377 1378 /* see if we have a cached copy */ 1379 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); 1380 1381 tmp_ctx = talloc_new(ldb); 1382 if (tmp_ctx == NULL) { 1383 goto failed; 1384 } 1385 1386 ntds_guid_new = talloc(tmp_ctx, struct GUID); 1387 if (!ntds_guid_new) { 1388 goto failed; 1389 } 1390 1391 *ntds_guid_new = *ntds_guid_in; 1392 1393 /* cache the domain_sid in the ldb */ 1394 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) { 1395 goto failed; 1396 } 1397 1398 talloc_steal(ldb, ntds_guid_new); 1399 talloc_free(tmp_ctx); 1400 talloc_free(ntds_guid_old); 1401 1402 return true; 1403 1404failed: 1405 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n")); 1406 talloc_free(tmp_ctx); 1407 return false; 1408} 1409 1410/* 1411 work out the server dn for the current open ldb 1412*/ 1413struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 1414{ 1415 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb)); 1416} 1417 1418/* 1419 work out the server dn for the current open ldb 1420*/ 1421struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 1422{ 1423 struct ldb_dn *server_dn; 1424 struct ldb_dn *server_site_dn; 1425 1426 server_dn = samdb_server_dn(ldb, mem_ctx); 1427 if (!server_dn) return NULL; 1428 1429 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn); 1430 1431 talloc_free(server_dn); 1432 return server_site_dn; 1433} 1434 1435/* 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 */ 1442bool 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 1489 return ret; 1490} 1491 1492/* 1493 work out if we are the PDC for the domain of the current open ldb 1494*/ 1495bool samdb_is_pdc(struct ldb_context *ldb) 1496{ 1497 const char *dom_attrs[] = { "fSMORoleOwner", NULL }; 1498 int ret; 1499 struct ldb_result *dom_res; 1500 TALLOC_CTX *tmp_ctx; 1501 bool is_pdc; 1502 struct ldb_dn *pdc; 1503 1504 tmp_ctx = talloc_new(ldb); 1505 if (tmp_ctx == NULL) { 1506 DEBUG(1, ("talloc_new failed in samdb_is_pdc")); 1507 return false; 1508 } 1509 1510 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL); 1511 if (ret) { 1512 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 1513 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 1514 ldb_errstring(ldb))); 1515 goto failed; 1516 } 1517 if (dom_res->count != 1) { 1518 goto failed; 1519 } 1520 1521 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner"); 1522 1523 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) { 1524 is_pdc = true; 1525 } else { 1526 is_pdc = false; 1527 } 1528 1529 talloc_free(tmp_ctx); 1530 1531 return is_pdc; 1532 1533failed: 1534 DEBUG(1,("Failed to find if we are the PDC for this ldb\n")); 1535 talloc_free(tmp_ctx); 1536 return false; 1537} 1538 1539/* 1540 work out if we are a Global Catalog server for the domain of the current open ldb 1541*/ 1542bool samdb_is_gc(struct ldb_context *ldb) 1543{ 1544 const char *attrs[] = { "options", NULL }; 1545 int ret, options; 1546 struct ldb_result *res; 1547 TALLOC_CTX *tmp_ctx; 1548 1549 tmp_ctx = talloc_new(ldb); 1550 if (tmp_ctx == NULL) { 1551 DEBUG(1, ("talloc_new failed in samdb_is_pdc")); 1552 return false; 1553 } 1554 1555 /* Query cn=ntds settings,.... */ 1556 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL); 1557 if (ret) { 1558 talloc_free(tmp_ctx); 1559 return false; 1560 } 1561 if (res->count != 1) { 1562 talloc_free(tmp_ctx); 1563 return false; 1564 } 1565 1566 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0); 1567 talloc_free(tmp_ctx); 1568 1569 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */ 1570 if (options & 0x000000001) { 1571 return true; 1572 } 1573 return false; 1574} 1575 1576/* Find a domain object in the parents of a particular DN. */ 1577int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, 1578 struct ldb_dn **parent_dn, const char **errstring) 1579{ 1580 TALLOC_CTX *local_ctx; 1581 struct ldb_dn *sdn = dn; 1582 struct ldb_result *res = NULL; 1583 int ret = 0; 1584 const char *attrs[] = { NULL }; 1585 1586 local_ctx = talloc_new(mem_ctx); 1587 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR; 1588 1589 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) { 1590 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs, 1591 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))"); 1592 if (ret == LDB_SUCCESS) { 1593 if (res->count == 1) { 1594 break; 1595 } 1596 } else { 1597 break; 1598 } 1599 } 1600 1601 if (ret != LDB_SUCCESS) { 1602 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s", 1603 ldb_dn_get_linearized(dn), 1604 ldb_dn_get_linearized(sdn), 1605 ldb_errstring(ldb)); 1606 talloc_free(local_ctx); 1607 return ret; 1608 } 1609 if (res->count != 1) { 1610 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object", 1611 ldb_dn_get_linearized(dn)); 1612 DEBUG(0,(__location__ ": %s\n", *errstring)); 1613 talloc_free(local_ctx); 1614 return LDB_ERR_CONSTRAINT_VIOLATION; 1615 } 1616 1617 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn); 1618 talloc_free(local_ctx); 1619 return ret; 1620} 1621 1622 1623/* 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*/ 1635NTSTATUS 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, 1639 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, 1644 struct samr_DomInfo1 **_dominfo) 1645{ 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; 1706 } 1707 } 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) { 1736 struct samr_DomInfo1 *dominfo; 1737 /* on failure we need to fill in the reject reasons */ 1738 dominfo = talloc(mem_ctx, struct samr_DomInfo1); 1739 if (dominfo == NULL) { 1740 return NT_STATUS_NO_MEMORY; 1741 } 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; 1747 *_dominfo = dominfo; 1748 } 1749 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; 1757 } 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; 1780 } 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*/ 1890NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, 1891 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, 1897 struct samr_DomInfo1 **_dominfo) 1898{ 1899 NTSTATUS nt_status; 1900 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))); 1907 return NT_STATUS_TRANSACTION_ABORTED; 1908 } 1909 1910 user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 1911 "(&(objectSid=%s)(objectClass=user))", 1912 ldap_encode_ndr_dom_sid(mem_ctx, user_sid)); 1913 if (!user_dn) { 1914 ldb_transaction_cancel(ctx); 1915 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n", 1916 dom_sid_string(mem_ctx, user_sid))); 1917 return NT_STATUS_NO_SUCH_USER; 1918 } 1919 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, 1933 user_dn, NULL, 1934 msg, new_pass, 1935 lmNewHash, ntNewHash, 1936 user_change, /* This is a password set, not change */ 1937 reject_reason, _dominfo); 1938 if (!NT_STATUS_IS_OK(nt_status)) { 1939 ldb_transaction_cancel(ctx); 1940 return nt_status; 1941 } 1942 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) { 1952 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n", 1953 ldb_dn_get_linearized(msg->dn), 1954 ldb_errstring(ctx))); 1955 return NT_STATUS_TRANSACTION_ABORTED; 1956 } 1957 return NT_STATUS_OK; 1958} 1959 1960 1961 1962NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 1963 struct dom_sid *sid, struct ldb_dn **ret_dn) 1964{ 1965 struct ldb_message *msg; 1966 struct ldb_dn *basedn; 1967 const char *sidstr; 1968 int ret; 1969 1970 sidstr = dom_sid_string(mem_ctx, sid); 1971 NT_STATUS_HAVE_NO_MEMORY(sidstr); 1972 1973 /* We might have to create a ForeignSecurityPrincipal, even if this user 1974 * is in our own domain */ 1975 1976 msg = ldb_msg_new(mem_ctx); 1977 if (msg == NULL) { 1978 return NT_STATUS_NO_MEMORY; 1979 } 1980 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) { 1991 DEBUG(0, ("Failed to find DN for " 1992 "ForeignSecurityPrincipal container\n")); 1993 return NT_STATUS_INTERNAL_DB_CORRUPTION; 1994 } 1995 1996 /* 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)) 1999 return NT_STATUS_NO_MEMORY; 2000 2001 samdb_msg_add_string(sam_ctx, mem_ctx, msg, 2002 "objectClass", 2003 "foreignSecurityPrincipal"); 2004 2005 /* create the alias */ 2006 ret = ldb_add(sam_ctx, msg); 2007 if (ret != 0) { 2008 DEBUG(0,("Failed to create foreignSecurityPrincipal " 2009 "record %s: %s\n", 2010 ldb_dn_get_linearized(msg->dn), 2011 ldb_errstring(sam_ctx))); 2012 return NT_STATUS_INTERNAL_DB_CORRUPTION; 2013 } 2014 *ret_dn = msg->dn; 2015 return NT_STATUS_OK; 2016} 2017 2018 2019/* 2020 Find the DN of a domain, assuming it to be a dotted.dns name 2021*/ 2022 2023struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 2024{ 2025 int i; 2026 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 2027 const char *binary_encoded; 2028 const char **split_realm; 2029 struct ldb_dn *dn; 2030 2031 if (!tmp_ctx) { 2032 return NULL; 2033 } 2034 2035 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, "."); 2036 if (!split_realm) { 2037 talloc_free(tmp_ctx); 2038 return NULL; 2039 } 2040 dn = ldb_dn_new(mem_ctx, ldb, NULL); 2041 for (i=0; split_realm[i]; i++) { 2042 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]); 2043 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) { 2044 DEBUG(2, ("Failed to add dc=%s element to DN %s\n", 2045 binary_encoded, ldb_dn_get_linearized(dn))); 2046 talloc_free(tmp_ctx); 2047 return NULL; 2048 } 2049 } 2050 if (!ldb_dn_validate(dn)) { 2051 DEBUG(2, ("Failed to validated DN %s\n", 2052 ldb_dn_get_linearized(dn))); 2053 return NULL; 2054 } 2055 return dn; 2056} 2057/* 2058 Find the DN of a domain, be it the netbios or DNS name 2059*/ 2060 2061struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 2062 const char *domain_name) 2063{ 2064 const char * const domain_ref_attrs[] = { 2065 "ncName", NULL 2066 }; 2067 const char * const domain_ref2_attrs[] = { 2068 NULL 2069 }; 2070 struct ldb_result *res_domain_ref; 2071 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name); 2072 /* find the domain's DN */ 2073 int ret_domain = ldb_search(ldb, mem_ctx, 2074 &res_domain_ref, 2075 samdb_partitions_dn(ldb, mem_ctx), 2076 LDB_SCOPE_ONELEVEL, 2077 domain_ref_attrs, 2078 "(&(nETBIOSName=%s)(objectclass=crossRef))", 2079 escaped_domain); 2080 if (ret_domain != 0) { 2081 return NULL; 2082 } 2083 2084 if (res_domain_ref->count == 0) { 2085 ret_domain = ldb_search(ldb, mem_ctx, 2086 &res_domain_ref, 2087 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name), 2088 LDB_SCOPE_BASE, 2089 domain_ref2_attrs, 2090 "(objectclass=domain)"); 2091 if (ret_domain != 0) { 2092 return NULL; 2093 } 2094 2095 if (res_domain_ref->count == 1) { 2096 return res_domain_ref->msgs[0]->dn; 2097 } 2098 return NULL; 2099 } 2100 2101 if (res_domain_ref->count > 1) { 2102 DEBUG(0,("Found %d records matching domain [%s]\n", 2103 ret_domain, domain_name)); 2104 return NULL; 2105 } 2106 2107 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL); 2108 2109} 2110 2111 2112/* 2113 use a GUID to find a DN 2114 */ 2115int dsdb_find_dn_by_guid(struct ldb_context *ldb, 2116 TALLOC_CTX *mem_ctx, 2117 const char *guid_str, struct ldb_dn **dn) 2118{ 2119 int ret; 2120 struct ldb_result *res; 2121 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); 2133 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, 2142 NULL, 2143 res, ldb_search_default_callback, 2144 NULL); 2145 if (ret != LDB_SUCCESS) { 2146 return ret; 2147 } 2148 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) { 2160 return ret; 2161 } 2162 2163 ret = ldb_request_add_control(search_req, 2164 LDB_CONTROL_SEARCH_OPTIONS_OID, 2165 true, options); 2166 if (ret != LDB_SUCCESS) { 2167 return ret; 2168 } 2169 2170 ret = ldb_request(ldb, search_req); 2171 if (ret != LDB_SUCCESS) { 2172 return ret; 2173 } 2174 2175 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL); 2176 if (ret != LDB_SUCCESS) { 2177 return ret; 2178 } 2179 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) { 2184 return LDB_ERR_NO_SUCH_OBJECT; 2185 } 2186 2187 *dn = res->msgs[0]->dn; 2188 2189 return LDB_SUCCESS; 2190} 2191 2192/* 2193 search for attrs on one DN, allowing for deleted objects 2194 */ 2195int 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; 2202 struct ldb_request *req; 2203 TALLOC_CTX *tmp_ctx; 2204 struct ldb_result *res; 2205 2206 tmp_ctx = talloc_new(mem_ctx); 2207 2208 res = talloc_zero(tmp_ctx, struct ldb_result); 2209 if (!res) { 2210 return LDB_ERR_OPERATIONS_ERROR; 2211 } 2212 2213 ret = ldb_build_search_req(&req, ldb, tmp_ctx, 2214 basedn, 2215 LDB_SCOPE_BASE, 2216 NULL, 2217 attrs, 2218 NULL, 2219 res, 2220 ldb_search_default_callback, 2221 NULL); 2222 if (ret != LDB_SUCCESS) { 2223 talloc_free(tmp_ctx); 2224 return ret; 2225 } 2226 2227 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL); 2228 if (ret != LDB_SUCCESS) { 2229 return ret; 2230 } 2231 2232 ret = ldb_request(ldb, req); 2233 if (ret == LDB_SUCCESS) { 2234 ret = ldb_wait(req->handle, LDB_WAIT_ALL); 2235 } 2236 2237 talloc_free(req); 2238 *_res = talloc_steal(mem_ctx, res); 2239 return ret; 2240} 2241 2242 2243/* 2244 use a DN to find a GUID 2245 */ 2246int dsdb_find_guid_by_dn(struct ldb_context *ldb, 2247 struct ldb_dn *dn, struct GUID *guid) 2248{ 2249 int ret; 2250 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 */ 2271int 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 */ 2307WERROR 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; 2312 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 GUID 2359 attr must be "repsFrom" or "repsTo" 2360 */ 2361WERROR 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 2404failed: 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 a 2412 partition 2413 */ 2414int 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 2422 res = talloc_zero(tmp_ctx, struct ldb_result); 2423 if (!res) { 2424 talloc_free(tmp_ctx); 2425 return LDB_ERR_OPERATIONS_ERROR; 2426 } 2427 2428 ret = ldb_build_search_req(&req, ldb, tmp_ctx, 2429 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"), 2430 LDB_SCOPE_BASE, 2431 NULL, NULL, 2432 NULL, 2433 res, ldb_search_default_callback, 2434 NULL); 2435 if (ret != LDB_SUCCESS) { 2436 talloc_free(tmp_ctx); 2437 return ret; 2438 } 2439 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); 2452 if (ret != LDB_SUCCESS) { 2453 talloc_free(tmp_ctx); 2454 return ret; 2455 } 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; 2468 talloc_free(tmp_ctx); 2469 return LDB_SUCCESS; 2470 } 2471 2472 if (ret != LDB_SUCCESS) { 2473 talloc_free(tmp_ctx); 2474 return ret; 2475 } 2476 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 2483 talloc_free(tmp_ctx); 2484 2485 return LDB_SUCCESS; 2486} 2487 2488/* 2489 save the uSNHighest attribute in the @REPLCHANGED object for a 2490 partition 2491 */ 2492int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN) 2493{ 2494 struct ldb_request *req; 2495 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); 2531again: 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 2565int 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} 2570