1/* 2 * Unix SMB/CIFS implementation. 3 * libnet Join Support 4 * Copyright (C) Gerald (Jerry) Carter 2006 5 * Copyright (C) Guenther Deschner 2007-2008 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21#include "includes.h" 22#include "libnet/libnet.h" 23#include "libcli/auth/libcli_auth.h" 24#include "../librpc/gen_ndr/cli_samr.h" 25#include "../librpc/gen_ndr/cli_lsa.h" 26 27/**************************************************************** 28****************************************************************/ 29 30#define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \ 31 do { \ 32 char *str = NULL; \ 33 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \ 34 DEBUG(1,("libnet_Join:\n%s", str)); \ 35 TALLOC_FREE(str); \ 36 } while (0) 37 38#define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \ 39 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES) 40#define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \ 41 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT) 42 43#define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \ 44 do { \ 45 char *str = NULL; \ 46 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \ 47 DEBUG(1,("libnet_Unjoin:\n%s", str)); \ 48 TALLOC_FREE(str); \ 49 } while (0) 50 51#define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \ 52 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES) 53#define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \ 54 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT) 55 56/**************************************************************** 57****************************************************************/ 58 59static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx, 60 struct libnet_JoinCtx *r, 61 const char *format, ...) 62{ 63 va_list args; 64 65 if (r->out.error_string) { 66 return; 67 } 68 69 va_start(args, format); 70 r->out.error_string = talloc_vasprintf(mem_ctx, format, args); 71 va_end(args); 72} 73 74/**************************************************************** 75****************************************************************/ 76 77static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx, 78 struct libnet_UnjoinCtx *r, 79 const char *format, ...) 80{ 81 va_list args; 82 83 if (r->out.error_string) { 84 return; 85 } 86 87 va_start(args, format); 88 r->out.error_string = talloc_vasprintf(mem_ctx, format, args); 89 va_end(args); 90} 91 92#ifdef WITH_ADS 93 94/**************************************************************** 95****************************************************************/ 96 97static ADS_STATUS libnet_connect_ads(const char *dns_domain_name, 98 const char *netbios_domain_name, 99 const char *dc_name, 100 const char *user_name, 101 const char *password, 102 ADS_STRUCT **ads) 103{ 104 ADS_STATUS status; 105 ADS_STRUCT *my_ads = NULL; 106 107 my_ads = ads_init(dns_domain_name, 108 netbios_domain_name, 109 dc_name); 110 if (!my_ads) { 111 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 112 } 113 114 if (user_name) { 115 SAFE_FREE(my_ads->auth.user_name); 116 my_ads->auth.user_name = SMB_STRDUP(user_name); 117 } 118 119 if (password) { 120 SAFE_FREE(my_ads->auth.password); 121 my_ads->auth.password = SMB_STRDUP(password); 122 } 123 124 status = ads_connect_user_creds(my_ads); 125 if (!ADS_ERR_OK(status)) { 126 ads_destroy(&my_ads); 127 return status; 128 } 129 130 *ads = my_ads; 131 return ADS_SUCCESS; 132} 133 134/**************************************************************** 135****************************************************************/ 136 137static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx, 138 struct libnet_JoinCtx *r) 139{ 140 ADS_STATUS status; 141 142 status = libnet_connect_ads(r->out.dns_domain_name, 143 r->out.netbios_domain_name, 144 r->in.dc_name, 145 r->in.admin_account, 146 r->in.admin_password, 147 &r->in.ads); 148 if (!ADS_ERR_OK(status)) { 149 libnet_join_set_error_string(mem_ctx, r, 150 "failed to connect to AD: %s", 151 ads_errstr(status)); 152 return status; 153 } 154 155 if (!r->out.netbios_domain_name) { 156 r->out.netbios_domain_name = talloc_strdup(mem_ctx, 157 r->in.ads->server.workgroup); 158 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name); 159 } 160 161 if (!r->out.dns_domain_name) { 162 r->out.dns_domain_name = talloc_strdup(mem_ctx, 163 r->in.ads->config.realm); 164 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name); 165 } 166 167 r->out.domain_is_ad = true; 168 169 return ADS_SUCCESS; 170} 171 172/**************************************************************** 173****************************************************************/ 174 175static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx, 176 struct libnet_UnjoinCtx *r) 177{ 178 ADS_STATUS status; 179 180 status = libnet_connect_ads(r->in.domain_name, 181 r->in.domain_name, 182 r->in.dc_name, 183 r->in.admin_account, 184 r->in.admin_password, 185 &r->in.ads); 186 if (!ADS_ERR_OK(status)) { 187 libnet_unjoin_set_error_string(mem_ctx, r, 188 "failed to connect to AD: %s", 189 ads_errstr(status)); 190 } 191 192 return status; 193} 194 195/**************************************************************** 196 join a domain using ADS (LDAP mods) 197****************************************************************/ 198 199static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx, 200 struct libnet_JoinCtx *r) 201{ 202 ADS_STATUS status; 203 LDAPMessage *res = NULL; 204 const char *attrs[] = { "dn", NULL }; 205 bool moved = false; 206 207 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou); 208 if (!ADS_ERR_OK(status)) { 209 return status; 210 } 211 212 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs); 213 if (!ADS_ERR_OK(status)) { 214 return status; 215 } 216 217 if (ads_count_replies(r->in.ads, res) != 1) { 218 ads_msgfree(r->in.ads, res); 219 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT); 220 } 221 222 ads_msgfree(r->in.ads, res); 223 224 /* Attempt to create the machine account and bail if this fails. 225 Assume that the admin wants exactly what they requested */ 226 227 status = ads_create_machine_acct(r->in.ads, 228 r->in.machine_name, 229 r->in.account_ou); 230 231 if (ADS_ERR_OK(status)) { 232 DEBUG(1,("machine account creation created\n")); 233 return status; 234 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) && 235 (status.err.rc == LDAP_ALREADY_EXISTS)) { 236 status = ADS_SUCCESS; 237 } 238 239 if (!ADS_ERR_OK(status)) { 240 DEBUG(1,("machine account creation failed\n")); 241 return status; 242 } 243 244 status = ads_move_machine_acct(r->in.ads, 245 r->in.machine_name, 246 r->in.account_ou, 247 &moved); 248 if (!ADS_ERR_OK(status)) { 249 DEBUG(1,("failure to locate/move pre-existing " 250 "machine account\n")); 251 return status; 252 } 253 254 DEBUG(1,("The machine account %s the specified OU.\n", 255 moved ? "was moved into" : "already exists in")); 256 257 return status; 258} 259 260/**************************************************************** 261****************************************************************/ 262 263static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx, 264 struct libnet_UnjoinCtx *r) 265{ 266 ADS_STATUS status; 267 268 if (!r->in.ads) { 269 status = libnet_unjoin_connect_ads(mem_ctx, r); 270 if (!ADS_ERR_OK(status)) { 271 libnet_unjoin_set_error_string(mem_ctx, r, 272 "failed to connect to AD: %s", 273 ads_errstr(status)); 274 return status; 275 } 276 } 277 278 status = ads_leave_realm(r->in.ads, r->in.machine_name); 279 if (!ADS_ERR_OK(status)) { 280 libnet_unjoin_set_error_string(mem_ctx, r, 281 "failed to leave realm: %s", 282 ads_errstr(status)); 283 return status; 284 } 285 286 return ADS_SUCCESS; 287} 288 289/**************************************************************** 290****************************************************************/ 291 292static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx, 293 struct libnet_JoinCtx *r) 294{ 295 ADS_STATUS status; 296 LDAPMessage *res = NULL; 297 char *dn = NULL; 298 299 if (!r->in.machine_name) { 300 return ADS_ERROR(LDAP_NO_MEMORY); 301 } 302 303 status = ads_find_machine_acct(r->in.ads, 304 &res, 305 r->in.machine_name); 306 if (!ADS_ERR_OK(status)) { 307 return status; 308 } 309 310 if (ads_count_replies(r->in.ads, res) != 1) { 311 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); 312 goto done; 313 } 314 315 dn = ads_get_dn(r->in.ads, mem_ctx, res); 316 if (!dn) { 317 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); 318 goto done; 319 } 320 321 r->out.dn = talloc_strdup(mem_ctx, dn); 322 if (!r->out.dn) { 323 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); 324 goto done; 325 } 326 327 done: 328 ads_msgfree(r->in.ads, res); 329 TALLOC_FREE(dn); 330 331 return status; 332} 333 334/**************************************************************** 335 Set a machines dNSHostName and servicePrincipalName attributes 336****************************************************************/ 337 338static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, 339 struct libnet_JoinCtx *r) 340{ 341 ADS_STATUS status; 342 ADS_MODLIST mods; 343 fstring my_fqdn; 344 const char *spn_array[3] = {NULL, NULL, NULL}; 345 char *spn = NULL; 346 347 /* Find our DN */ 348 349 status = libnet_join_find_machine_acct(mem_ctx, r); 350 if (!ADS_ERR_OK(status)) { 351 return status; 352 } 353 354 /* Windows only creates HOST/shortname & HOST/fqdn. */ 355 356 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name); 357 if (!spn) { 358 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 359 } 360 strupper_m(spn); 361 spn_array[0] = spn; 362 363 if (!name_to_fqdn(my_fqdn, r->in.machine_name) 364 || (strchr(my_fqdn, '.') == NULL)) { 365 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, 366 r->out.dns_domain_name); 367 } 368 369 strlower_m(my_fqdn); 370 371 if (!strequal(my_fqdn, r->in.machine_name)) { 372 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); 373 if (!spn) { 374 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 375 } 376 spn_array[1] = spn; 377 } 378 379 mods = ads_init_mods(mem_ctx); 380 if (!mods) { 381 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 382 } 383 384 /* fields of primary importance */ 385 386 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn); 387 if (!ADS_ERR_OK(status)) { 388 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 389 } 390 391 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName", 392 spn_array); 393 if (!ADS_ERR_OK(status)) { 394 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 395 } 396 397 return ads_gen_mod(r->in.ads, r->out.dn, mods); 398} 399 400/**************************************************************** 401****************************************************************/ 402 403static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx, 404 struct libnet_JoinCtx *r) 405{ 406 ADS_STATUS status; 407 ADS_MODLIST mods; 408 409 if (!r->in.create_upn) { 410 return ADS_SUCCESS; 411 } 412 413 /* Find our DN */ 414 415 status = libnet_join_find_machine_acct(mem_ctx, r); 416 if (!ADS_ERR_OK(status)) { 417 return status; 418 } 419 420 if (!r->in.upn) { 421 r->in.upn = talloc_asprintf(mem_ctx, 422 "host/%s@%s", 423 r->in.machine_name, 424 r->out.dns_domain_name); 425 if (!r->in.upn) { 426 return ADS_ERROR(LDAP_NO_MEMORY); 427 } 428 } 429 430 /* now do the mods */ 431 432 mods = ads_init_mods(mem_ctx); 433 if (!mods) { 434 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 435 } 436 437 /* fields of primary importance */ 438 439 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn); 440 if (!ADS_ERR_OK(status)) { 441 return ADS_ERROR_LDAP(LDAP_NO_MEMORY); 442 } 443 444 return ads_gen_mod(r->in.ads, r->out.dn, mods); 445} 446 447 448/**************************************************************** 449****************************************************************/ 450 451static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx, 452 struct libnet_JoinCtx *r) 453{ 454 ADS_STATUS status; 455 ADS_MODLIST mods; 456 char *os_sp = NULL; 457 458 if (!r->in.os_name || !r->in.os_version ) { 459 return ADS_SUCCESS; 460 } 461 462 /* Find our DN */ 463 464 status = libnet_join_find_machine_acct(mem_ctx, r); 465 if (!ADS_ERR_OK(status)) { 466 return status; 467 } 468 469 /* now do the mods */ 470 471 mods = ads_init_mods(mem_ctx); 472 if (!mods) { 473 return ADS_ERROR(LDAP_NO_MEMORY); 474 } 475 476 os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string()); 477 if (!os_sp) { 478 return ADS_ERROR(LDAP_NO_MEMORY); 479 } 480 481 /* fields of primary importance */ 482 483 status = ads_mod_str(mem_ctx, &mods, "operatingSystem", 484 r->in.os_name); 485 if (!ADS_ERR_OK(status)) { 486 return status; 487 } 488 489 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion", 490 r->in.os_version); 491 if (!ADS_ERR_OK(status)) { 492 return status; 493 } 494 495 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack", 496 os_sp); 497 if (!ADS_ERR_OK(status)) { 498 return status; 499 } 500 501 return ads_gen_mod(r->in.ads, r->out.dn, mods); 502} 503 504/**************************************************************** 505****************************************************************/ 506 507static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx, 508 struct libnet_JoinCtx *r) 509{ 510 if (!USE_SYSTEM_KEYTAB) { 511 return true; 512 } 513 514 if (ads_keytab_create_default(r->in.ads) != 0) { 515 return false; 516 } 517 518 return true; 519} 520 521/**************************************************************** 522****************************************************************/ 523 524static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx, 525 struct libnet_JoinCtx *r) 526{ 527 uint32_t domain_func; 528 ADS_STATUS status; 529 const char *salt = NULL; 530 char *std_salt = NULL; 531 532 status = ads_domain_func_level(r->in.ads, &domain_func); 533 if (!ADS_ERR_OK(status)) { 534 libnet_join_set_error_string(mem_ctx, r, 535 "failed to determine domain functional level: %s", 536 ads_errstr(status)); 537 return false; 538 } 539 540 /* go ahead and setup the default salt */ 541 542 std_salt = kerberos_standard_des_salt(); 543 if (!std_salt) { 544 libnet_join_set_error_string(mem_ctx, r, 545 "failed to obtain standard DES salt"); 546 return false; 547 } 548 549 salt = talloc_strdup(mem_ctx, std_salt); 550 if (!salt) { 551 return false; 552 } 553 554 SAFE_FREE(std_salt); 555 556 /* if it's a Windows functional domain, we have to look for the UPN */ 557 558 if (domain_func == DS_DOMAIN_FUNCTION_2000) { 559 char *upn; 560 561 upn = ads_get_upn(r->in.ads, mem_ctx, 562 r->in.machine_name); 563 if (upn) { 564 salt = talloc_strdup(mem_ctx, upn); 565 if (!salt) { 566 return false; 567 } 568 } 569 } 570 571 return kerberos_secrets_store_des_salt(salt); 572} 573 574/**************************************************************** 575****************************************************************/ 576 577static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx, 578 struct libnet_JoinCtx *r) 579{ 580 ADS_STATUS status; 581 582 if (!r->in.ads) { 583 status = libnet_join_connect_ads(mem_ctx, r); 584 if (!ADS_ERR_OK(status)) { 585 return status; 586 } 587 } 588 589 status = libnet_join_set_machine_spn(mem_ctx, r); 590 if (!ADS_ERR_OK(status)) { 591 libnet_join_set_error_string(mem_ctx, r, 592 "failed to set machine spn: %s", 593 ads_errstr(status)); 594 return status; 595 } 596 597 status = libnet_join_set_os_attributes(mem_ctx, r); 598 if (!ADS_ERR_OK(status)) { 599 libnet_join_set_error_string(mem_ctx, r, 600 "failed to set machine os attributes: %s", 601 ads_errstr(status)); 602 return status; 603 } 604 605 status = libnet_join_set_machine_upn(mem_ctx, r); 606 if (!ADS_ERR_OK(status)) { 607 libnet_join_set_error_string(mem_ctx, r, 608 "failed to set machine upn: %s", 609 ads_errstr(status)); 610 return status; 611 } 612 613 if (!libnet_join_derive_salting_principal(mem_ctx, r)) { 614 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); 615 } 616 617 if (!libnet_join_create_keytab(mem_ctx, r)) { 618 libnet_join_set_error_string(mem_ctx, r, 619 "failed to create kerberos keytab"); 620 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); 621 } 622 623 return ADS_SUCCESS; 624} 625#endif /* WITH_ADS */ 626 627/**************************************************************** 628 Store the machine password and domain SID 629****************************************************************/ 630 631static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx, 632 struct libnet_JoinCtx *r) 633{ 634 if (!secrets_store_domain_sid(r->out.netbios_domain_name, 635 r->out.domain_sid)) 636 { 637 DEBUG(1,("Failed to save domain sid\n")); 638 return false; 639 } 640 641 if (!secrets_store_machine_password(r->in.machine_password, 642 r->out.netbios_domain_name, 643 r->in.secure_channel_type)) 644 { 645 DEBUG(1,("Failed to save machine password\n")); 646 return false; 647 } 648 649 return true; 650} 651 652/**************************************************************** 653 Connect dc's IPC$ share 654****************************************************************/ 655 656static NTSTATUS libnet_join_connect_dc_ipc(const char *dc, 657 const char *user, 658 const char *pass, 659 bool use_kerberos, 660 struct cli_state **cli) 661{ 662 int flags = 0; 663 664 if (use_kerberos) { 665 flags |= CLI_FULL_CONNECTION_USE_KERBEROS; 666 } 667 668 if (use_kerberos && pass) { 669 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; 670 } 671 672 return cli_full_connection(cli, NULL, 673 dc, 674 NULL, 0, 675 "IPC$", "IPC", 676 user, 677 NULL, 678 pass, 679 flags, 680 Undefined, NULL); 681} 682 683/**************************************************************** 684 Lookup domain dc's info 685****************************************************************/ 686 687static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx, 688 struct libnet_JoinCtx *r, 689 struct cli_state **cli) 690{ 691 struct rpc_pipe_client *pipe_hnd = NULL; 692 struct policy_handle lsa_pol; 693 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 694 union lsa_PolicyInformation *info = NULL; 695 696 status = libnet_join_connect_dc_ipc(r->in.dc_name, 697 r->in.admin_account, 698 r->in.admin_password, 699 r->in.use_kerberos, 700 cli); 701 if (!NT_STATUS_IS_OK(status)) { 702 goto done; 703 } 704 705 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id, 706 &pipe_hnd); 707 if (!NT_STATUS_IS_OK(status)) { 708 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n", 709 nt_errstr(status))); 710 goto done; 711 } 712 713 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true, 714 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol); 715 if (!NT_STATUS_IS_OK(status)) { 716 goto done; 717 } 718 719 status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx, 720 &lsa_pol, 721 LSA_POLICY_INFO_DNS, 722 &info); 723 if (NT_STATUS_IS_OK(status)) { 724 r->out.domain_is_ad = true; 725 r->out.netbios_domain_name = info->dns.name.string; 726 r->out.dns_domain_name = info->dns.dns_domain.string; 727 r->out.forest_name = info->dns.dns_forest.string; 728 r->out.domain_sid = sid_dup_talloc(mem_ctx, info->dns.sid); 729 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid); 730 } 731 732 if (!NT_STATUS_IS_OK(status)) { 733 status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx, 734 &lsa_pol, 735 LSA_POLICY_INFO_ACCOUNT_DOMAIN, 736 &info); 737 if (!NT_STATUS_IS_OK(status)) { 738 goto done; 739 } 740 741 r->out.netbios_domain_name = info->account_domain.name.string; 742 r->out.domain_sid = sid_dup_talloc(mem_ctx, info->account_domain.sid); 743 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid); 744 } 745 746 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol); 747 TALLOC_FREE(pipe_hnd); 748 749 done: 750 return status; 751} 752 753/**************************************************************** 754 Do the domain join unsecure 755****************************************************************/ 756 757static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx, 758 struct libnet_JoinCtx *r, 759 struct cli_state *cli) 760{ 761 struct rpc_pipe_client *pipe_hnd = NULL; 762 unsigned char orig_trust_passwd_hash[16]; 763 unsigned char new_trust_passwd_hash[16]; 764 fstring trust_passwd; 765 NTSTATUS status; 766 767 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id, 768 &pipe_hnd); 769 if (!NT_STATUS_IS_OK(status)) { 770 return status; 771 } 772 773 if (!r->in.machine_password) { 774 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); 775 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password); 776 } 777 778 E_md4hash(r->in.machine_password, new_trust_passwd_hash); 779 780 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */ 781 fstrcpy(trust_passwd, r->in.admin_password); 782 strlower_m(trust_passwd); 783 784 /* 785 * Machine names can be 15 characters, but the max length on 786 * a password is 14. --jerry 787 */ 788 789 trust_passwd[14] = '\0'; 790 791 E_md4hash(trust_passwd, orig_trust_passwd_hash); 792 793 status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx, 794 r->in.machine_name, 795 orig_trust_passwd_hash, 796 r->in.machine_password, 797 new_trust_passwd_hash, 798 r->in.secure_channel_type); 799 800 return status; 801} 802 803/**************************************************************** 804 Do the domain join 805****************************************************************/ 806 807static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx, 808 struct libnet_JoinCtx *r, 809 struct cli_state *cli) 810{ 811 struct rpc_pipe_client *pipe_hnd = NULL; 812 struct policy_handle sam_pol, domain_pol, user_pol; 813 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 814 char *acct_name; 815 struct lsa_String lsa_acct_name; 816 uint32_t user_rid; 817 uint32_t acct_flags = ACB_WSTRUST; 818 struct samr_Ids user_rids; 819 struct samr_Ids name_types; 820 union samr_UserInfo user_info; 821 822 struct samr_CryptPassword crypt_pwd; 823 struct samr_CryptPasswordEx crypt_pwd_ex; 824 825 ZERO_STRUCT(sam_pol); 826 ZERO_STRUCT(domain_pol); 827 ZERO_STRUCT(user_pol); 828 829 switch (r->in.secure_channel_type) { 830 case SEC_CHAN_WKSTA: 831 acct_flags = ACB_WSTRUST; 832 break; 833 case SEC_CHAN_BDC: 834 acct_flags = ACB_SVRTRUST; 835 break; 836 default: 837 return NT_STATUS_INVALID_PARAMETER; 838 } 839 840 if (!r->in.machine_password) { 841 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); 842 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password); 843 } 844 845 /* Open the domain */ 846 847 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id, 848 &pipe_hnd); 849 if (!NT_STATUS_IS_OK(status)) { 850 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n", 851 nt_errstr(status))); 852 goto done; 853 } 854 855 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx, 856 pipe_hnd->desthost, 857 SAMR_ACCESS_ENUM_DOMAINS 858 | SAMR_ACCESS_LOOKUP_DOMAIN, 859 &sam_pol); 860 if (!NT_STATUS_IS_OK(status)) { 861 goto done; 862 } 863 864 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx, 865 &sam_pol, 866 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 867 | SAMR_DOMAIN_ACCESS_CREATE_USER 868 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, 869 r->out.domain_sid, 870 &domain_pol); 871 if (!NT_STATUS_IS_OK(status)) { 872 goto done; 873 } 874 875 /* Create domain user */ 876 877 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name); 878 strlower_m(acct_name); 879 880 init_lsa_String(&lsa_acct_name, acct_name); 881 882 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) { 883 uint32_t access_desired = 884 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE | 885 SEC_STD_WRITE_DAC | SEC_STD_DELETE | 886 SAMR_USER_ACCESS_SET_PASSWORD | 887 SAMR_USER_ACCESS_GET_ATTRIBUTES | 888 SAMR_USER_ACCESS_SET_ATTRIBUTES; 889 uint32_t access_granted = 0; 890 891 DEBUG(10,("Creating account with desired access mask: %d\n", 892 access_desired)); 893 894 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx, 895 &domain_pol, 896 &lsa_acct_name, 897 acct_flags, 898 access_desired, 899 &user_pol, 900 &access_granted, 901 &user_rid); 902 if (!NT_STATUS_IS_OK(status) && 903 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { 904 905 DEBUG(10,("Creation of workstation account failed: %s\n", 906 nt_errstr(status))); 907 908 /* If NT_STATUS_ACCESS_DENIED then we have a valid 909 username/password combo but the user does not have 910 administrator access. */ 911 912 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { 913 libnet_join_set_error_string(mem_ctx, r, 914 "User specified does not have " 915 "administrator privileges"); 916 } 917 918 goto done; 919 } 920 921 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { 922 if (!(r->in.join_flags & 923 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) { 924 goto done; 925 } 926 } 927 928 /* We *must* do this.... don't ask... */ 929 930 if (NT_STATUS_IS_OK(status)) { 931 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol); 932 } 933 } 934 935 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx, 936 &domain_pol, 937 1, 938 &lsa_acct_name, 939 &user_rids, 940 &name_types); 941 if (!NT_STATUS_IS_OK(status)) { 942 goto done; 943 } 944 945 if (name_types.ids[0] != SID_NAME_USER) { 946 DEBUG(0,("%s is not a user account (type=%d)\n", 947 acct_name, name_types.ids[0])); 948 status = NT_STATUS_INVALID_WORKSTATION; 949 goto done; 950 } 951 952 user_rid = user_rids.ids[0]; 953 954 /* Open handle on user */ 955 956 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx, 957 &domain_pol, 958 SEC_FLAG_MAXIMUM_ALLOWED, 959 user_rid, 960 &user_pol); 961 if (!NT_STATUS_IS_OK(status)) { 962 goto done; 963 } 964 965 /* Fill in the additional account flags now */ 966 967 acct_flags |= ACB_PWNOEXP; 968 if (r->out.domain_is_ad) { 969#if !defined(ENCTYPE_ARCFOUR_HMAC) 970 acct_flags |= ACB_USE_DES_KEY_ONLY; 971#endif 972 ;; 973 } 974 975 /* Set account flags on machine account */ 976 ZERO_STRUCT(user_info.info16); 977 user_info.info16.acct_flags = acct_flags; 978 979 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx, 980 &user_pol, 981 16, 982 &user_info); 983 984 if (!NT_STATUS_IS_OK(status)) { 985 986 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx, 987 &user_pol); 988 989 libnet_join_set_error_string(mem_ctx, r, 990 "Failed to set account flags for machine account (%s)\n", 991 nt_errstr(status)); 992 goto done; 993 } 994 995 /* Set password on machine account - first try level 26 */ 996 997 init_samr_CryptPasswordEx(r->in.machine_password, 998 &cli->user_session_key, 999 &crypt_pwd_ex); 1000 1001 user_info.info26.password = crypt_pwd_ex; 1002 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON; 1003 1004 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx, 1005 &user_pol, 1006 26, 1007 &user_info); 1008 1009 if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) { 1010 1011 /* retry with level 24 */ 1012 1013 init_samr_CryptPassword(r->in.machine_password, 1014 &cli->user_session_key, 1015 &crypt_pwd); 1016 1017 user_info.info24.password = crypt_pwd; 1018 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON; 1019 1020 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx, 1021 &user_pol, 1022 24, 1023 &user_info); 1024 } 1025 1026 if (!NT_STATUS_IS_OK(status)) { 1027 1028 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx, 1029 &user_pol); 1030 1031 libnet_join_set_error_string(mem_ctx, r, 1032 "Failed to set password for machine account (%s)\n", 1033 nt_errstr(status)); 1034 goto done; 1035 } 1036 1037 status = NT_STATUS_OK; 1038 1039 done: 1040 if (!pipe_hnd) { 1041 return status; 1042 } 1043 1044 if (is_valid_policy_hnd(&sam_pol)) { 1045 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol); 1046 } 1047 if (is_valid_policy_hnd(&domain_pol)) { 1048 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol); 1049 } 1050 if (is_valid_policy_hnd(&user_pol)) { 1051 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol); 1052 } 1053 TALLOC_FREE(pipe_hnd); 1054 1055 return status; 1056} 1057 1058/**************************************************************** 1059****************************************************************/ 1060 1061NTSTATUS libnet_join_ok(const char *netbios_domain_name, 1062 const char *machine_name, 1063 const char *dc_name) 1064{ 1065 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; 1066 struct cli_state *cli = NULL; 1067 struct rpc_pipe_client *pipe_hnd = NULL; 1068 struct rpc_pipe_client *netlogon_pipe = NULL; 1069 NTSTATUS status; 1070 char *machine_password = NULL; 1071 char *machine_account = NULL; 1072 1073 if (!dc_name) { 1074 return NT_STATUS_INVALID_PARAMETER; 1075 } 1076 1077 if (!secrets_init()) { 1078 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 1079 } 1080 1081 machine_password = secrets_fetch_machine_password(netbios_domain_name, 1082 NULL, NULL); 1083 if (!machine_password) { 1084 return NT_STATUS_NO_TRUST_LSA_SECRET; 1085 } 1086 1087 if (asprintf(&machine_account, "%s$", machine_name) == -1) { 1088 SAFE_FREE(machine_password); 1089 return NT_STATUS_NO_MEMORY; 1090 } 1091 1092 status = cli_full_connection(&cli, NULL, 1093 dc_name, 1094 NULL, 0, 1095 "IPC$", "IPC", 1096 machine_account, 1097 NULL, 1098 machine_password, 1099 0, 1100 Undefined, NULL); 1101 free(machine_account); 1102 free(machine_password); 1103 1104 if (!NT_STATUS_IS_OK(status)) { 1105 status = cli_full_connection(&cli, NULL, 1106 dc_name, 1107 NULL, 0, 1108 "IPC$", "IPC", 1109 "", 1110 NULL, 1111 "", 1112 0, 1113 Undefined, NULL); 1114 } 1115 1116 if (!NT_STATUS_IS_OK(status)) { 1117 return status; 1118 } 1119 1120 status = get_schannel_session_key(cli, netbios_domain_name, 1121 &neg_flags, &netlogon_pipe); 1122 if (!NT_STATUS_IS_OK(status)) { 1123 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) { 1124 cli_shutdown(cli); 1125 return NT_STATUS_OK; 1126 } 1127 1128 DEBUG(0,("libnet_join_ok: failed to get schannel session " 1129 "key from server %s for domain %s. Error was %s\n", 1130 cli->desthost, netbios_domain_name, nt_errstr(status))); 1131 cli_shutdown(cli); 1132 return status; 1133 } 1134 1135 if (!lp_client_schannel()) { 1136 cli_shutdown(cli); 1137 return NT_STATUS_OK; 1138 } 1139 1140 status = cli_rpc_pipe_open_schannel_with_key( 1141 cli, &ndr_table_netlogon.syntax_id, NCACN_NP, 1142 DCERPC_AUTH_LEVEL_PRIVACY, 1143 netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd); 1144 1145 cli_shutdown(cli); 1146 1147 if (!NT_STATUS_IS_OK(status)) { 1148 DEBUG(0,("libnet_join_ok: failed to open schannel session " 1149 "on netlogon pipe to server %s for domain %s. " 1150 "Error was %s\n", 1151 cli->desthost, netbios_domain_name, nt_errstr(status))); 1152 return status; 1153 } 1154 1155 return NT_STATUS_OK; 1156} 1157 1158/**************************************************************** 1159****************************************************************/ 1160 1161static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx, 1162 struct libnet_JoinCtx *r) 1163{ 1164 NTSTATUS status; 1165 1166 status = libnet_join_ok(r->out.netbios_domain_name, 1167 r->in.machine_name, 1168 r->in.dc_name); 1169 if (!NT_STATUS_IS_OK(status)) { 1170 libnet_join_set_error_string(mem_ctx, r, 1171 "failed to verify domain membership after joining: %s", 1172 get_friendly_nt_error_msg(status)); 1173 return WERR_SETUP_NOT_JOINED; 1174 } 1175 1176 return WERR_OK; 1177} 1178 1179/**************************************************************** 1180****************************************************************/ 1181 1182static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx, 1183 struct libnet_UnjoinCtx *r) 1184{ 1185 if (!secrets_delete_machine_password_ex(lp_workgroup())) { 1186 return false; 1187 } 1188 1189 if (!secrets_delete_domain_sid(lp_workgroup())) { 1190 return false; 1191 } 1192 1193 return true; 1194} 1195 1196/**************************************************************** 1197****************************************************************/ 1198 1199static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx, 1200 struct libnet_UnjoinCtx *r) 1201{ 1202 struct cli_state *cli = NULL; 1203 struct rpc_pipe_client *pipe_hnd = NULL; 1204 struct policy_handle sam_pol, domain_pol, user_pol; 1205 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 1206 char *acct_name; 1207 uint32_t user_rid; 1208 struct lsa_String lsa_acct_name; 1209 struct samr_Ids user_rids; 1210 struct samr_Ids name_types; 1211 union samr_UserInfo *info = NULL; 1212 1213 ZERO_STRUCT(sam_pol); 1214 ZERO_STRUCT(domain_pol); 1215 ZERO_STRUCT(user_pol); 1216 1217 status = libnet_join_connect_dc_ipc(r->in.dc_name, 1218 r->in.admin_account, 1219 r->in.admin_password, 1220 r->in.use_kerberos, 1221 &cli); 1222 if (!NT_STATUS_IS_OK(status)) { 1223 goto done; 1224 } 1225 1226 /* Open the domain */ 1227 1228 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id, 1229 &pipe_hnd); 1230 if (!NT_STATUS_IS_OK(status)) { 1231 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n", 1232 nt_errstr(status))); 1233 goto done; 1234 } 1235 1236 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx, 1237 pipe_hnd->desthost, 1238 SEC_FLAG_MAXIMUM_ALLOWED, 1239 &sam_pol); 1240 if (!NT_STATUS_IS_OK(status)) { 1241 goto done; 1242 } 1243 1244 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx, 1245 &sam_pol, 1246 SEC_FLAG_MAXIMUM_ALLOWED, 1247 r->in.domain_sid, 1248 &domain_pol); 1249 if (!NT_STATUS_IS_OK(status)) { 1250 goto done; 1251 } 1252 1253 /* Create domain user */ 1254 1255 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name); 1256 strlower_m(acct_name); 1257 1258 init_lsa_String(&lsa_acct_name, acct_name); 1259 1260 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx, 1261 &domain_pol, 1262 1, 1263 &lsa_acct_name, 1264 &user_rids, 1265 &name_types); 1266 1267 if (!NT_STATUS_IS_OK(status)) { 1268 goto done; 1269 } 1270 1271 if (name_types.ids[0] != SID_NAME_USER) { 1272 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, 1273 name_types.ids[0])); 1274 status = NT_STATUS_INVALID_WORKSTATION; 1275 goto done; 1276 } 1277 1278 user_rid = user_rids.ids[0]; 1279 1280 /* Open handle on user */ 1281 1282 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx, 1283 &domain_pol, 1284 SEC_FLAG_MAXIMUM_ALLOWED, 1285 user_rid, 1286 &user_pol); 1287 if (!NT_STATUS_IS_OK(status)) { 1288 goto done; 1289 } 1290 1291 /* Get user info */ 1292 1293 status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx, 1294 &user_pol, 1295 16, 1296 &info); 1297 if (!NT_STATUS_IS_OK(status)) { 1298 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol); 1299 goto done; 1300 } 1301 1302 /* now disable and setuser info */ 1303 1304 info->info16.acct_flags |= ACB_DISABLED; 1305 1306 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx, 1307 &user_pol, 1308 16, 1309 info); 1310 1311 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol); 1312 1313done: 1314 if (pipe_hnd) { 1315 if (is_valid_policy_hnd(&domain_pol)) { 1316 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol); 1317 } 1318 if (is_valid_policy_hnd(&sam_pol)) { 1319 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol); 1320 } 1321 TALLOC_FREE(pipe_hnd); 1322 } 1323 1324 if (cli) { 1325 cli_shutdown(cli); 1326 } 1327 1328 return status; 1329} 1330 1331/**************************************************************** 1332****************************************************************/ 1333 1334static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r) 1335{ 1336 WERROR werr; 1337 struct smbconf_ctx *ctx; 1338 1339 werr = smbconf_init_reg(r, &ctx, NULL); 1340 if (!W_ERROR_IS_OK(werr)) { 1341 goto done; 1342 } 1343 1344 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) { 1345 1346 werr = smbconf_set_global_parameter(ctx, "security", "user"); 1347 W_ERROR_NOT_OK_GOTO_DONE(werr); 1348 1349 werr = smbconf_set_global_parameter(ctx, "workgroup", 1350 r->in.domain_name); 1351 1352 smbconf_delete_global_parameter(ctx, "realm"); 1353 goto done; 1354 } 1355 1356 werr = smbconf_set_global_parameter(ctx, "security", "domain"); 1357 W_ERROR_NOT_OK_GOTO_DONE(werr); 1358 1359 werr = smbconf_set_global_parameter(ctx, "workgroup", 1360 r->out.netbios_domain_name); 1361 W_ERROR_NOT_OK_GOTO_DONE(werr); 1362 1363 if (r->out.domain_is_ad) { 1364 werr = smbconf_set_global_parameter(ctx, "security", "ads"); 1365 W_ERROR_NOT_OK_GOTO_DONE(werr); 1366 1367 werr = smbconf_set_global_parameter(ctx, "realm", 1368 r->out.dns_domain_name); 1369 W_ERROR_NOT_OK_GOTO_DONE(werr); 1370 } 1371 1372 done: 1373 smbconf_shutdown(ctx); 1374 return werr; 1375} 1376 1377/**************************************************************** 1378****************************************************************/ 1379 1380static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r) 1381{ 1382 WERROR werr = WERR_OK; 1383 struct smbconf_ctx *ctx; 1384 1385 werr = smbconf_init_reg(r, &ctx, NULL); 1386 if (!W_ERROR_IS_OK(werr)) { 1387 goto done; 1388 } 1389 1390 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) { 1391 1392 werr = smbconf_set_global_parameter(ctx, "security", "user"); 1393 W_ERROR_NOT_OK_GOTO_DONE(werr); 1394 1395 werr = smbconf_delete_global_parameter(ctx, "workgroup"); 1396 W_ERROR_NOT_OK_GOTO_DONE(werr); 1397 1398 smbconf_delete_global_parameter(ctx, "realm"); 1399 } 1400 1401 done: 1402 smbconf_shutdown(ctx); 1403 return werr; 1404} 1405 1406/**************************************************************** 1407****************************************************************/ 1408 1409static WERROR do_JoinConfig(struct libnet_JoinCtx *r) 1410{ 1411 WERROR werr; 1412 1413 if (!W_ERROR_IS_OK(r->out.result)) { 1414 return r->out.result; 1415 } 1416 1417 if (!r->in.modify_config) { 1418 return WERR_OK; 1419 } 1420 1421 werr = do_join_modify_vals_config(r); 1422 if (!W_ERROR_IS_OK(werr)) { 1423 return werr; 1424 } 1425 1426 lp_load(get_dyn_CONFIGFILE(),true,false,false,true); 1427 1428 r->out.modified_config = true; 1429 r->out.result = werr; 1430 1431 return werr; 1432} 1433 1434/**************************************************************** 1435****************************************************************/ 1436 1437static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r) 1438{ 1439 WERROR werr; 1440 1441 if (!W_ERROR_IS_OK(r->out.result)) { 1442 return r->out.result; 1443 } 1444 1445 if (!r->in.modify_config) { 1446 return WERR_OK; 1447 } 1448 1449 werr = do_unjoin_modify_vals_config(r); 1450 if (!W_ERROR_IS_OK(werr)) { 1451 return werr; 1452 } 1453 1454 lp_load(get_dyn_CONFIGFILE(),true,false,false,true); 1455 1456 r->out.modified_config = true; 1457 r->out.result = werr; 1458 1459 return werr; 1460} 1461 1462/**************************************************************** 1463****************************************************************/ 1464 1465static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx, 1466 const char *domain_str, 1467 const char **domain_p, 1468 const char **dc_p) 1469{ 1470 char *domain = NULL; 1471 char *dc = NULL; 1472 const char *p = NULL; 1473 1474 if (!domain_str || !domain_p || !dc_p) { 1475 return false; 1476 } 1477 1478 p = strchr_m(domain_str, '\\'); 1479 1480 if (p != NULL) { 1481 domain = talloc_strndup(mem_ctx, domain_str, 1482 PTR_DIFF(p, domain_str)); 1483 dc = talloc_strdup(mem_ctx, p+1); 1484 if (!dc) { 1485 return false; 1486 } 1487 } else { 1488 domain = talloc_strdup(mem_ctx, domain_str); 1489 dc = NULL; 1490 } 1491 if (!domain) { 1492 return false; 1493 } 1494 1495 *domain_p = domain; 1496 1497 if (!*dc_p && dc) { 1498 *dc_p = dc; 1499 } 1500 1501 return true; 1502} 1503 1504/**************************************************************** 1505****************************************************************/ 1506 1507static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx, 1508 struct libnet_JoinCtx *r) 1509{ 1510 if (!r->in.domain_name) { 1511 libnet_join_set_error_string(mem_ctx, r, 1512 "No domain name defined"); 1513 return WERR_INVALID_PARAM; 1514 } 1515 1516 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name, 1517 &r->in.domain_name, 1518 &r->in.dc_name)) { 1519 libnet_join_set_error_string(mem_ctx, r, 1520 "Failed to parse domain name"); 1521 return WERR_INVALID_PARAM; 1522 } 1523 1524 if (IS_DC) { 1525 return WERR_SETUP_DOMAIN_CONTROLLER; 1526 } 1527 1528 if (!secrets_init()) { 1529 libnet_join_set_error_string(mem_ctx, r, 1530 "Unable to open secrets database"); 1531 return WERR_CAN_NOT_COMPLETE; 1532 } 1533 1534 return WERR_OK; 1535} 1536 1537/**************************************************************** 1538****************************************************************/ 1539 1540static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid) 1541{ 1542 NTSTATUS status; 1543 1544 /* Try adding dom admins to builtin\admins. Only log failures. */ 1545 status = create_builtin_administrators(domain_sid); 1546 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) { 1547 DEBUG(10,("Unable to auto-add domain administrators to " 1548 "BUILTIN\\Administrators during join because " 1549 "winbindd must be running.")); 1550 } else if (!NT_STATUS_IS_OK(status)) { 1551 DEBUG(5, ("Failed to auto-add domain administrators to " 1552 "BUILTIN\\Administrators during join: %s\n", 1553 nt_errstr(status))); 1554 } 1555 1556 /* Try adding dom users to builtin\users. Only log failures. */ 1557 status = create_builtin_users(domain_sid); 1558 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) { 1559 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users " 1560 "during join because winbindd must be running.")); 1561 } else if (!NT_STATUS_IS_OK(status)) { 1562 DEBUG(5, ("Failed to auto-add domain administrators to " 1563 "BUILTIN\\Administrators during join: %s\n", 1564 nt_errstr(status))); 1565 } 1566} 1567 1568/**************************************************************** 1569****************************************************************/ 1570 1571static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx, 1572 struct libnet_JoinCtx *r) 1573{ 1574 WERROR werr; 1575 1576 if (!W_ERROR_IS_OK(r->out.result)) { 1577 return r->out.result; 1578 } 1579 1580 werr = do_JoinConfig(r); 1581 if (!W_ERROR_IS_OK(werr)) { 1582 return werr; 1583 } 1584 1585 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) { 1586 return WERR_OK; 1587 } 1588 1589 saf_join_store(r->out.netbios_domain_name, r->in.dc_name); 1590 if (r->out.dns_domain_name) { 1591 saf_join_store(r->out.dns_domain_name, r->in.dc_name); 1592 } 1593 1594#ifdef WITH_ADS 1595 if (r->out.domain_is_ad && 1596 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) { 1597 ADS_STATUS ads_status; 1598 1599 ads_status = libnet_join_post_processing_ads(mem_ctx, r); 1600 if (!ADS_ERR_OK(ads_status)) { 1601 return WERR_GENERAL_FAILURE; 1602 } 1603 } 1604#endif /* WITH_ADS */ 1605 1606 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid); 1607 1608 return WERR_OK; 1609} 1610 1611/**************************************************************** 1612****************************************************************/ 1613 1614static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r) 1615{ 1616 const char *krb5_cc_env = NULL; 1617 1618 if (r->in.ads) { 1619 ads_destroy(&r->in.ads); 1620 } 1621 1622 krb5_cc_env = getenv(KRB5_ENV_CCNAME); 1623 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) { 1624 unsetenv(KRB5_ENV_CCNAME); 1625 } 1626 1627 return 0; 1628} 1629 1630/**************************************************************** 1631****************************************************************/ 1632 1633static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r) 1634{ 1635 const char *krb5_cc_env = NULL; 1636 1637 if (r->in.ads) { 1638 ads_destroy(&r->in.ads); 1639 } 1640 1641 krb5_cc_env = getenv(KRB5_ENV_CCNAME); 1642 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) { 1643 unsetenv(KRB5_ENV_CCNAME); 1644 } 1645 1646 return 0; 1647} 1648 1649/**************************************************************** 1650****************************************************************/ 1651 1652WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx, 1653 struct libnet_JoinCtx **r) 1654{ 1655 struct libnet_JoinCtx *ctx; 1656 const char *krb5_cc_env = NULL; 1657 1658 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx); 1659 if (!ctx) { 1660 return WERR_NOMEM; 1661 } 1662 1663 talloc_set_destructor(ctx, libnet_destroy_JoinCtx); 1664 1665 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname()); 1666 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name); 1667 1668 krb5_cc_env = getenv(KRB5_ENV_CCNAME); 1669 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) { 1670 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin"); 1671 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env); 1672 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1); 1673 } 1674 1675 ctx->in.secure_channel_type = SEC_CHAN_WKSTA; 1676 1677 *r = ctx; 1678 1679 return WERR_OK; 1680} 1681 1682/**************************************************************** 1683****************************************************************/ 1684 1685WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx, 1686 struct libnet_UnjoinCtx **r) 1687{ 1688 struct libnet_UnjoinCtx *ctx; 1689 const char *krb5_cc_env = NULL; 1690 1691 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx); 1692 if (!ctx) { 1693 return WERR_NOMEM; 1694 } 1695 1696 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx); 1697 1698 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname()); 1699 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name); 1700 1701 krb5_cc_env = getenv(KRB5_ENV_CCNAME); 1702 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) { 1703 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin"); 1704 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env); 1705 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1); 1706 } 1707 1708 *r = ctx; 1709 1710 return WERR_OK; 1711} 1712 1713/**************************************************************** 1714****************************************************************/ 1715 1716static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx, 1717 struct libnet_JoinCtx *r) 1718{ 1719 bool valid_security = false; 1720 bool valid_workgroup = false; 1721 bool valid_realm = false; 1722 1723 /* check if configuration is already set correctly */ 1724 1725 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name); 1726 1727 switch (r->out.domain_is_ad) { 1728 case false: 1729 valid_security = (lp_security() == SEC_DOMAIN); 1730 if (valid_workgroup && valid_security) { 1731 /* nothing to be done */ 1732 return WERR_OK; 1733 } 1734 break; 1735 case true: 1736 valid_realm = strequal(lp_realm(), r->out.dns_domain_name); 1737 switch (lp_security()) { 1738 case SEC_DOMAIN: 1739 case SEC_ADS: 1740 valid_security = true; 1741 } 1742 1743 if (valid_workgroup && valid_realm && valid_security) { 1744 /* nothing to be done */ 1745 return WERR_OK; 1746 } 1747 break; 1748 } 1749 1750 /* check if we are supposed to manipulate configuration */ 1751 1752 if (!r->in.modify_config) { 1753 1754 char *wrong_conf = talloc_strdup(mem_ctx, ""); 1755 1756 if (!valid_workgroup) { 1757 wrong_conf = talloc_asprintf_append(wrong_conf, 1758 "\"workgroup\" set to '%s', should be '%s'", 1759 lp_workgroup(), r->out.netbios_domain_name); 1760 W_ERROR_HAVE_NO_MEMORY(wrong_conf); 1761 } 1762 1763 if (!valid_realm) { 1764 wrong_conf = talloc_asprintf_append(wrong_conf, 1765 "\"realm\" set to '%s', should be '%s'", 1766 lp_realm(), r->out.dns_domain_name); 1767 W_ERROR_HAVE_NO_MEMORY(wrong_conf); 1768 } 1769 1770 if (!valid_security) { 1771 const char *sec = NULL; 1772 switch (lp_security()) { 1773 case SEC_SHARE: sec = "share"; break; 1774 case SEC_USER: sec = "user"; break; 1775 case SEC_DOMAIN: sec = "domain"; break; 1776 case SEC_ADS: sec = "ads"; break; 1777 } 1778 wrong_conf = talloc_asprintf_append(wrong_conf, 1779 "\"security\" set to '%s', should be %s", 1780 sec, r->out.domain_is_ad ? 1781 "either 'domain' or 'ads'" : "'domain'"); 1782 W_ERROR_HAVE_NO_MEMORY(wrong_conf); 1783 } 1784 1785 libnet_join_set_error_string(mem_ctx, r, 1786 "Invalid configuration (%s) and configuration modification " 1787 "was not requested", wrong_conf); 1788 return WERR_CAN_NOT_COMPLETE; 1789 } 1790 1791 /* check if we are able to manipulate configuration */ 1792 1793 if (!lp_config_backend_is_registry()) { 1794 libnet_join_set_error_string(mem_ctx, r, 1795 "Configuration manipulation requested but not " 1796 "supported by backend"); 1797 return WERR_NOT_SUPPORTED; 1798 } 1799 1800 return WERR_OK; 1801} 1802 1803/**************************************************************** 1804****************************************************************/ 1805 1806static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx, 1807 struct libnet_JoinCtx *r) 1808{ 1809 NTSTATUS status; 1810 WERROR werr; 1811 struct cli_state *cli = NULL; 1812#ifdef WITH_ADS 1813 ADS_STATUS ads_status; 1814#endif /* WITH_ADS */ 1815 1816 if (!r->in.dc_name) { 1817 struct netr_DsRGetDCNameInfo *info; 1818 const char *dc; 1819 status = dsgetdcname(mem_ctx, 1820 r->in.msg_ctx, 1821 r->in.domain_name, 1822 NULL, 1823 NULL, 1824 DS_FORCE_REDISCOVERY | 1825 DS_DIRECTORY_SERVICE_REQUIRED | 1826 DS_WRITABLE_REQUIRED | 1827 DS_RETURN_DNS_NAME, 1828 &info); 1829 if (!NT_STATUS_IS_OK(status)) { 1830 libnet_join_set_error_string(mem_ctx, r, 1831 "failed to find DC for domain %s", 1832 r->in.domain_name, 1833 get_friendly_nt_error_msg(status)); 1834 return WERR_DCNOTFOUND; 1835 } 1836 1837 dc = strip_hostname(info->dc_unc); 1838 r->in.dc_name = talloc_strdup(mem_ctx, dc); 1839 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name); 1840 } 1841 1842 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli); 1843 if (!NT_STATUS_IS_OK(status)) { 1844 libnet_join_set_error_string(mem_ctx, r, 1845 "failed to lookup DC info for domain '%s' over rpc: %s", 1846 r->in.domain_name, get_friendly_nt_error_msg(status)); 1847 return ntstatus_to_werror(status); 1848 } 1849 1850 werr = libnet_join_check_config(mem_ctx, r); 1851 if (!W_ERROR_IS_OK(werr)) { 1852 goto done; 1853 } 1854 1855#ifdef WITH_ADS 1856 if (r->out.domain_is_ad && r->in.account_ou && 1857 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) { 1858 1859 ads_status = libnet_join_connect_ads(mem_ctx, r); 1860 if (!ADS_ERR_OK(ads_status)) { 1861 return WERR_DEFAULT_JOIN_REQUIRED; 1862 } 1863 1864 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r); 1865 if (!ADS_ERR_OK(ads_status)) { 1866 libnet_join_set_error_string(mem_ctx, r, 1867 "failed to precreate account in ou %s: %s", 1868 r->in.account_ou, 1869 ads_errstr(ads_status)); 1870 return WERR_DEFAULT_JOIN_REQUIRED; 1871 } 1872 1873 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE; 1874 } 1875#endif /* WITH_ADS */ 1876 1877 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) && 1878 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) { 1879 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli); 1880 } else { 1881 status = libnet_join_joindomain_rpc(mem_ctx, r, cli); 1882 } 1883 if (!NT_STATUS_IS_OK(status)) { 1884 libnet_join_set_error_string(mem_ctx, r, 1885 "failed to join domain '%s' over rpc: %s", 1886 r->in.domain_name, get_friendly_nt_error_msg(status)); 1887 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { 1888 return WERR_SETUP_ALREADY_JOINED; 1889 } 1890 werr = ntstatus_to_werror(status); 1891 goto done; 1892 } 1893 1894 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) { 1895 werr = WERR_SETUP_NOT_JOINED; 1896 goto done; 1897 } 1898 1899 werr = WERR_OK; 1900 1901 done: 1902 if (cli) { 1903 cli_shutdown(cli); 1904 } 1905 1906 return werr; 1907} 1908 1909/**************************************************************** 1910****************************************************************/ 1911 1912static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx, 1913 struct libnet_JoinCtx *r) 1914{ 1915 WERROR werr; 1916 struct libnet_UnjoinCtx *u = NULL; 1917 1918 werr = libnet_init_UnjoinCtx(mem_ctx, &u); 1919 if (!W_ERROR_IS_OK(werr)) { 1920 return werr; 1921 } 1922 1923 u->in.debug = r->in.debug; 1924 u->in.dc_name = r->in.dc_name; 1925 u->in.domain_name = r->in.domain_name; 1926 u->in.admin_account = r->in.admin_account; 1927 u->in.admin_password = r->in.admin_password; 1928 u->in.modify_config = r->in.modify_config; 1929 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE | 1930 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE; 1931 1932 werr = libnet_Unjoin(mem_ctx, u); 1933 TALLOC_FREE(u); 1934 1935 return werr; 1936} 1937 1938/**************************************************************** 1939****************************************************************/ 1940 1941WERROR libnet_Join(TALLOC_CTX *mem_ctx, 1942 struct libnet_JoinCtx *r) 1943{ 1944 WERROR werr; 1945 1946 if (r->in.debug) { 1947 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r); 1948 } 1949 1950 werr = libnet_join_pre_processing(mem_ctx, r); 1951 if (!W_ERROR_IS_OK(werr)) { 1952 goto done; 1953 } 1954 1955 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) { 1956 werr = libnet_DomainJoin(mem_ctx, r); 1957 if (!W_ERROR_IS_OK(werr)) { 1958 goto done; 1959 } 1960 } 1961 1962 werr = libnet_join_post_processing(mem_ctx, r); 1963 if (!W_ERROR_IS_OK(werr)) { 1964 goto done; 1965 } 1966 1967 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) { 1968 werr = libnet_join_post_verify(mem_ctx, r); 1969 if (!W_ERROR_IS_OK(werr)) { 1970 libnet_join_rollback(mem_ctx, r); 1971 } 1972 } 1973 1974 done: 1975 r->out.result = werr; 1976 1977 if (r->in.debug) { 1978 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r); 1979 } 1980 return werr; 1981} 1982 1983/**************************************************************** 1984****************************************************************/ 1985 1986static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx, 1987 struct libnet_UnjoinCtx *r) 1988{ 1989 NTSTATUS status; 1990 1991 if (!r->in.domain_sid) { 1992 struct dom_sid sid; 1993 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) { 1994 libnet_unjoin_set_error_string(mem_ctx, r, 1995 "Unable to fetch domain sid: are we joined?"); 1996 return WERR_SETUP_NOT_JOINED; 1997 } 1998 r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid); 1999 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid); 2000 } 2001 2002 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) && 2003 !r->in.delete_machine_account) { 2004 libnet_join_unjoindomain_remove_secrets(mem_ctx, r); 2005 return WERR_OK; 2006 } 2007 2008 if (!r->in.dc_name) { 2009 struct netr_DsRGetDCNameInfo *info; 2010 const char *dc; 2011 status = dsgetdcname(mem_ctx, 2012 r->in.msg_ctx, 2013 r->in.domain_name, 2014 NULL, 2015 NULL, 2016 DS_DIRECTORY_SERVICE_REQUIRED | 2017 DS_WRITABLE_REQUIRED | 2018 DS_RETURN_DNS_NAME, 2019 &info); 2020 if (!NT_STATUS_IS_OK(status)) { 2021 libnet_unjoin_set_error_string(mem_ctx, r, 2022 "failed to find DC for domain %s", 2023 r->in.domain_name, 2024 get_friendly_nt_error_msg(status)); 2025 return WERR_DCNOTFOUND; 2026 } 2027 2028 dc = strip_hostname(info->dc_unc); 2029 r->in.dc_name = talloc_strdup(mem_ctx, dc); 2030 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name); 2031 } 2032 2033#ifdef WITH_ADS 2034 /* for net ads leave, try to delete the account. If it works, 2035 no sense in disabling. If it fails, we can still try to 2036 disable it. jmcd */ 2037 2038 if (r->in.delete_machine_account) { 2039 ADS_STATUS ads_status; 2040 ads_status = libnet_unjoin_connect_ads(mem_ctx, r); 2041 if (ADS_ERR_OK(ads_status)) { 2042 /* dirty hack */ 2043 r->out.dns_domain_name = 2044 talloc_strdup(mem_ctx, 2045 r->in.ads->server.realm); 2046 ads_status = 2047 libnet_unjoin_remove_machine_acct(mem_ctx, r); 2048 } 2049 if (!ADS_ERR_OK(ads_status)) { 2050 libnet_unjoin_set_error_string(mem_ctx, r, 2051 "failed to remove machine account from AD: %s", 2052 ads_errstr(ads_status)); 2053 } else { 2054 r->out.deleted_machine_account = true; 2055 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name); 2056 libnet_join_unjoindomain_remove_secrets(mem_ctx, r); 2057 return WERR_OK; 2058 } 2059 } 2060#endif /* WITH_ADS */ 2061 2062 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means 2063 "disable". */ 2064 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) { 2065 status = libnet_join_unjoindomain_rpc(mem_ctx, r); 2066 if (!NT_STATUS_IS_OK(status)) { 2067 libnet_unjoin_set_error_string(mem_ctx, r, 2068 "failed to disable machine account via rpc: %s", 2069 get_friendly_nt_error_msg(status)); 2070 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { 2071 return WERR_SETUP_NOT_JOINED; 2072 } 2073 return ntstatus_to_werror(status); 2074 } 2075 2076 r->out.disabled_machine_account = true; 2077 } 2078 2079 /* If disable succeeded or was not requested at all, we 2080 should be getting rid of our end of things */ 2081 2082 libnet_join_unjoindomain_remove_secrets(mem_ctx, r); 2083 2084 return WERR_OK; 2085} 2086 2087/**************************************************************** 2088****************************************************************/ 2089 2090static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx, 2091 struct libnet_UnjoinCtx *r) 2092{ 2093 if (!r->in.domain_name) { 2094 libnet_unjoin_set_error_string(mem_ctx, r, 2095 "No domain name defined"); 2096 return WERR_INVALID_PARAM; 2097 } 2098 2099 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name, 2100 &r->in.domain_name, 2101 &r->in.dc_name)) { 2102 libnet_unjoin_set_error_string(mem_ctx, r, 2103 "Failed to parse domain name"); 2104 return WERR_INVALID_PARAM; 2105 } 2106 2107 if (IS_DC) { 2108 return WERR_SETUP_DOMAIN_CONTROLLER; 2109 } 2110 2111 if (!secrets_init()) { 2112 libnet_unjoin_set_error_string(mem_ctx, r, 2113 "Unable to open secrets database"); 2114 return WERR_CAN_NOT_COMPLETE; 2115 } 2116 2117 return WERR_OK; 2118} 2119 2120/**************************************************************** 2121****************************************************************/ 2122 2123static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx, 2124 struct libnet_UnjoinCtx *r) 2125{ 2126 saf_delete(r->out.netbios_domain_name); 2127 saf_delete(r->out.dns_domain_name); 2128 2129 return libnet_unjoin_config(r); 2130} 2131 2132/**************************************************************** 2133****************************************************************/ 2134 2135WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx, 2136 struct libnet_UnjoinCtx *r) 2137{ 2138 WERROR werr; 2139 2140 if (r->in.debug) { 2141 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r); 2142 } 2143 2144 werr = libnet_unjoin_pre_processing(mem_ctx, r); 2145 if (!W_ERROR_IS_OK(werr)) { 2146 goto done; 2147 } 2148 2149 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) { 2150 werr = libnet_DomainUnjoin(mem_ctx, r); 2151 if (!W_ERROR_IS_OK(werr)) { 2152 libnet_unjoin_config(r); 2153 goto done; 2154 } 2155 } 2156 2157 werr = libnet_unjoin_post_processing(mem_ctx, r); 2158 if (!W_ERROR_IS_OK(werr)) { 2159 goto done; 2160 } 2161 2162 done: 2163 r->out.result = werr; 2164 2165 if (r->in.debug) { 2166 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r); 2167 } 2168 2169 return werr; 2170} 2171