2 * Unix SMB/CIFS implementation.
4 * Copyright (C) Gerald (Jerry) Carter 2006
5 * Copyright (C) Guenther Deschner 2007-2008
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.
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.
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/>.
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"
27 /****************************************************************
28 ****************************************************************/
30 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
33 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
34 DEBUG(1,("libnet_Join:\n%s", str)); \
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)
43 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
46 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
47 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
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)
56 /****************************************************************
57 ****************************************************************/
59 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
60 struct libnet_JoinCtx *r,
61 const char *format, ...)
65 if (r->out.error_string) {
69 va_start(args, format);
70 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
74 /****************************************************************
75 ****************************************************************/
77 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
78 struct libnet_UnjoinCtx *r,
79 const char *format, ...)
83 if (r->out.error_string) {
87 va_start(args, format);
88 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
94 /****************************************************************
95 ****************************************************************/
97 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
98 const char *netbios_domain_name,
100 const char *user_name,
101 const char *password,
105 ADS_STRUCT *my_ads = NULL;
107 my_ads = ads_init(dns_domain_name,
111 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
115 SAFE_FREE(my_ads->auth.user_name);
116 my_ads->auth.user_name = SMB_STRDUP(user_name);
120 SAFE_FREE(my_ads->auth.password);
121 my_ads->auth.password = SMB_STRDUP(password);
124 status = ads_connect_user_creds(my_ads);
125 if (!ADS_ERR_OK(status)) {
126 ads_destroy(&my_ads);
134 /****************************************************************
135 ****************************************************************/
137 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
138 struct libnet_JoinCtx *r)
142 status = libnet_connect_ads(r->out.dns_domain_name,
143 r->out.netbios_domain_name,
146 r->in.admin_password,
148 if (!ADS_ERR_OK(status)) {
149 libnet_join_set_error_string(mem_ctx, r,
150 "failed to connect to AD: %s",
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);
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);
167 r->out.domain_is_ad = true;
172 /****************************************************************
173 ****************************************************************/
175 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
176 struct libnet_UnjoinCtx *r)
180 status = libnet_connect_ads(r->in.domain_name,
184 r->in.admin_password,
186 if (!ADS_ERR_OK(status)) {
187 libnet_unjoin_set_error_string(mem_ctx, r,
188 "failed to connect to AD: %s",
195 /****************************************************************
196 join a domain using ADS (LDAP mods)
197 ****************************************************************/
199 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
200 struct libnet_JoinCtx *r)
203 LDAPMessage *res = NULL;
204 const char *attrs[] = { "dn", NULL };
207 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
208 if (!ADS_ERR_OK(status)) {
212 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
213 if (!ADS_ERR_OK(status)) {
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);
222 ads_msgfree(r->in.ads, res);
224 /* Attempt to create the machine account and bail if this fails.
225 Assume that the admin wants exactly what they requested */
227 status = ads_create_machine_acct(r->in.ads,
231 if (ADS_ERR_OK(status)) {
232 DEBUG(1,("machine account creation created\n"));
234 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
235 (status.err.rc == LDAP_ALREADY_EXISTS)) {
236 status = ADS_SUCCESS;
239 if (!ADS_ERR_OK(status)) {
240 DEBUG(1,("machine account creation failed\n"));
244 status = ads_move_machine_acct(r->in.ads,
248 if (!ADS_ERR_OK(status)) {
249 DEBUG(1,("failure to locate/move pre-existing "
250 "machine account\n"));
254 DEBUG(1,("The machine account %s the specified OU.\n",
255 moved ? "was moved into" : "already exists in"));
260 /****************************************************************
261 ****************************************************************/
263 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
264 struct libnet_UnjoinCtx *r)
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",
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",
289 /****************************************************************
290 ****************************************************************/
292 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
293 struct libnet_JoinCtx *r)
296 LDAPMessage *res = NULL;
299 if (!r->in.machine_name) {
300 return ADS_ERROR(LDAP_NO_MEMORY);
303 status = ads_find_machine_acct(r->in.ads,
306 if (!ADS_ERR_OK(status)) {
310 if (ads_count_replies(r->in.ads, res) != 1) {
311 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
315 dn = ads_get_dn(r->in.ads, mem_ctx, res);
317 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
321 r->out.dn = talloc_strdup(mem_ctx, dn);
323 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
328 ads_msgfree(r->in.ads, res);
334 /****************************************************************
335 Set a machines dNSHostName and servicePrincipalName attributes
336 ****************************************************************/
338 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
339 struct libnet_JoinCtx *r)
344 const char *spn_array[3] = {NULL, NULL, NULL};
349 status = libnet_join_find_machine_acct(mem_ctx, r);
350 if (!ADS_ERR_OK(status)) {
354 /* Windows only creates HOST/shortname & HOST/fqdn. */
356 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
358 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
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);
371 if (!strequal(my_fqdn, r->in.machine_name)) {
372 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
374 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
379 mods = ads_init_mods(mem_ctx);
381 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
384 /* fields of primary importance */
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);
391 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
393 if (!ADS_ERR_OK(status)) {
394 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
397 return ads_gen_mod(r->in.ads, r->out.dn, mods);
400 /****************************************************************
401 ****************************************************************/
403 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
404 struct libnet_JoinCtx *r)
409 if (!r->in.create_upn) {
415 status = libnet_join_find_machine_acct(mem_ctx, r);
416 if (!ADS_ERR_OK(status)) {
421 r->in.upn = talloc_asprintf(mem_ctx,
424 r->out.dns_domain_name);
426 return ADS_ERROR(LDAP_NO_MEMORY);
430 /* now do the mods */
432 mods = ads_init_mods(mem_ctx);
434 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
437 /* fields of primary importance */
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);
444 return ads_gen_mod(r->in.ads, r->out.dn, mods);
448 /****************************************************************
449 ****************************************************************/
451 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
452 struct libnet_JoinCtx *r)
458 if (!r->in.os_name || !r->in.os_version ) {
464 status = libnet_join_find_machine_acct(mem_ctx, r);
465 if (!ADS_ERR_OK(status)) {
469 /* now do the mods */
471 mods = ads_init_mods(mem_ctx);
473 return ADS_ERROR(LDAP_NO_MEMORY);
476 os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
478 return ADS_ERROR(LDAP_NO_MEMORY);
481 /* fields of primary importance */
483 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
485 if (!ADS_ERR_OK(status)) {
489 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
491 if (!ADS_ERR_OK(status)) {
495 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
497 if (!ADS_ERR_OK(status)) {
501 return ads_gen_mod(r->in.ads, r->out.dn, mods);
504 /****************************************************************
505 ****************************************************************/
507 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
508 struct libnet_JoinCtx *r)
510 if (!USE_SYSTEM_KEYTAB) {
514 if (ads_keytab_create_default(r->in.ads) != 0) {
521 /****************************************************************
522 ****************************************************************/
524 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
525 struct libnet_JoinCtx *r)
527 uint32_t domain_func;
529 const char *salt = NULL;
530 char *std_salt = NULL;
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",
540 /* go ahead and setup the default salt */
542 std_salt = kerberos_standard_des_salt();
544 libnet_join_set_error_string(mem_ctx, r,
545 "failed to obtain standard DES salt");
549 salt = talloc_strdup(mem_ctx, std_salt);
556 /* if it's a Windows functional domain, we have to look for the UPN */
558 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
561 upn = ads_get_upn(r->in.ads, mem_ctx,
564 salt = talloc_strdup(mem_ctx, upn);
571 return kerberos_secrets_store_des_salt(salt);
574 /****************************************************************
575 ****************************************************************/
577 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
578 struct libnet_JoinCtx *r)
583 status = libnet_join_connect_ads(mem_ctx, r);
584 if (!ADS_ERR_OK(status)) {
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",
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",
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",
613 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
614 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
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);
625 #endif /* WITH_ADS */
627 /****************************************************************
628 Store the machine password and domain SID
629 ****************************************************************/
631 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
632 struct libnet_JoinCtx *r)
634 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
637 DEBUG(1,("Failed to save domain sid\n"));
641 if (!secrets_store_machine_password(r->in.machine_password,
642 r->out.netbios_domain_name,
643 r->in.secure_channel_type))
645 DEBUG(1,("Failed to save machine password\n"));
652 /****************************************************************
653 Connect dc's IPC$ share
654 ****************************************************************/
656 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
660 struct cli_state **cli)
665 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
668 if (use_kerberos && pass) {
669 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
672 return cli_full_connection(cli, NULL,
683 /****************************************************************
684 Lookup domain dc's info
685 ****************************************************************/
687 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
688 struct libnet_JoinCtx *r,
689 struct cli_state **cli)
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;
696 status = libnet_join_connect_dc_ipc(r->in.dc_name,
698 r->in.admin_password,
701 if (!NT_STATUS_IS_OK(status)) {
705 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
707 if (!NT_STATUS_IS_OK(status)) {
708 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
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)) {
719 status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx,
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);
732 if (!NT_STATUS_IS_OK(status)) {
733 status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
735 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
737 if (!NT_STATUS_IS_OK(status)) {
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);
746 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
747 TALLOC_FREE(pipe_hnd);
753 /****************************************************************
754 Do the domain join unsecure
755 ****************************************************************/
757 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
758 struct libnet_JoinCtx *r,
759 struct cli_state *cli)
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;
767 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
769 if (!NT_STATUS_IS_OK(status)) {
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);
778 E_md4hash(r->in.machine_password, new_trust_passwd_hash);
780 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
781 fstrcpy(trust_passwd, r->in.admin_password);
782 strlower_m(trust_passwd);
785 * Machine names can be 15 characters, but the max length on
786 * a password is 14. --jerry
789 trust_passwd[14] = '\0';
791 E_md4hash(trust_passwd, orig_trust_passwd_hash);
793 status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx,
795 orig_trust_passwd_hash,
796 r->in.machine_password,
797 new_trust_passwd_hash,
798 r->in.secure_channel_type);
803 /****************************************************************
805 ****************************************************************/
807 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
808 struct libnet_JoinCtx *r,
809 struct cli_state *cli)
811 struct rpc_pipe_client *pipe_hnd = NULL;
812 struct policy_handle sam_pol, domain_pol, user_pol;
813 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
815 struct lsa_String lsa_acct_name;
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;
822 struct samr_CryptPassword crypt_pwd;
823 struct samr_CryptPasswordEx crypt_pwd_ex;
825 ZERO_STRUCT(sam_pol);
826 ZERO_STRUCT(domain_pol);
827 ZERO_STRUCT(user_pol);
829 switch (r->in.secure_channel_type) {
831 acct_flags = ACB_WSTRUST;
834 acct_flags = ACB_SVRTRUST;
837 return NT_STATUS_INVALID_PARAMETER;
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);
845 /* Open the domain */
847 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
849 if (!NT_STATUS_IS_OK(status)) {
850 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
855 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
857 SAMR_ACCESS_ENUM_DOMAINS
858 | SAMR_ACCESS_LOOKUP_DOMAIN,
860 if (!NT_STATUS_IS_OK(status)) {
864 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
866 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
867 | SAMR_DOMAIN_ACCESS_CREATE_USER
868 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
871 if (!NT_STATUS_IS_OK(status)) {
875 /* Create domain user */
877 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
878 strlower_m(acct_name);
880 init_lsa_String(&lsa_acct_name, acct_name);
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;
891 DEBUG(10,("Creating account with desired access mask: %d\n",
894 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
902 if (!NT_STATUS_IS_OK(status) &&
903 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
905 DEBUG(10,("Creation of workstation account failed: %s\n",
908 /* If NT_STATUS_ACCESS_DENIED then we have a valid
909 username/password combo but the user does not have
910 administrator access. */
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");
921 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
922 if (!(r->in.join_flags &
923 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
928 /* We *must* do this.... don't ask... */
930 if (NT_STATUS_IS_OK(status)) {
931 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
935 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
941 if (!NT_STATUS_IS_OK(status)) {
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;
952 user_rid = user_rids.ids[0];
954 /* Open handle on user */
956 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
958 SEC_FLAG_MAXIMUM_ALLOWED,
961 if (!NT_STATUS_IS_OK(status)) {
965 /* Fill in the additional account flags now */
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;
975 /* Set account flags on machine account */
976 ZERO_STRUCT(user_info.info16);
977 user_info.info16.acct_flags = acct_flags;
979 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
984 if (!NT_STATUS_IS_OK(status)) {
986 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
989 libnet_join_set_error_string(mem_ctx, r,
990 "Failed to set account flags for machine account (%s)\n",
995 /* Set password on machine account - first try level 26 */
997 init_samr_CryptPasswordEx(r->in.machine_password,
998 &cli->user_session_key,
1001 user_info.info26.password = crypt_pwd_ex;
1002 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1004 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1009 if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
1011 /* retry with level 24 */
1013 init_samr_CryptPassword(r->in.machine_password,
1014 &cli->user_session_key,
1017 user_info.info24.password = crypt_pwd;
1018 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1020 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1026 if (!NT_STATUS_IS_OK(status)) {
1028 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
1031 libnet_join_set_error_string(mem_ctx, r,
1032 "Failed to set password for machine account (%s)\n",
1037 status = NT_STATUS_OK;
1044 if (is_valid_policy_hnd(&sam_pol)) {
1045 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1047 if (is_valid_policy_hnd(&domain_pol)) {
1048 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1050 if (is_valid_policy_hnd(&user_pol)) {
1051 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1053 TALLOC_FREE(pipe_hnd);
1058 /****************************************************************
1059 ****************************************************************/
1061 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
1062 const char *machine_name,
1063 const char *dc_name)
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;
1070 char *machine_password = NULL;
1071 char *machine_account = NULL;
1074 return NT_STATUS_INVALID_PARAMETER;
1077 if (!secrets_init()) {
1078 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1081 machine_password = secrets_fetch_machine_password(netbios_domain_name,
1083 if (!machine_password) {
1084 return NT_STATUS_NO_TRUST_LSA_SECRET;
1087 if (asprintf(&machine_account, "%s$", machine_name) == -1) {
1088 SAFE_FREE(machine_password);
1089 return NT_STATUS_NO_MEMORY;
1092 status = cli_full_connection(&cli, NULL,
1101 free(machine_account);
1102 free(machine_password);
1104 if (!NT_STATUS_IS_OK(status)) {
1105 status = cli_full_connection(&cli, NULL,
1116 if (!NT_STATUS_IS_OK(status)) {
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)) {
1125 return NT_STATUS_OK;
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)));
1135 if (!lp_client_schannel()) {
1137 return NT_STATUS_OK;
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);
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. "
1151 cli->desthost, netbios_domain_name, nt_errstr(status)));
1155 return NT_STATUS_OK;
1158 /****************************************************************
1159 ****************************************************************/
1161 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1162 struct libnet_JoinCtx *r)
1166 status = libnet_join_ok(r->out.netbios_domain_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;
1179 /****************************************************************
1180 ****************************************************************/
1182 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1183 struct libnet_UnjoinCtx *r)
1185 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1189 if (!secrets_delete_domain_sid(lp_workgroup())) {
1196 /****************************************************************
1197 ****************************************************************/
1199 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1200 struct libnet_UnjoinCtx *r)
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;
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;
1213 ZERO_STRUCT(sam_pol);
1214 ZERO_STRUCT(domain_pol);
1215 ZERO_STRUCT(user_pol);
1217 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1218 r->in.admin_account,
1219 r->in.admin_password,
1222 if (!NT_STATUS_IS_OK(status)) {
1226 /* Open the domain */
1228 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
1230 if (!NT_STATUS_IS_OK(status)) {
1231 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1232 nt_errstr(status)));
1236 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1238 SEC_FLAG_MAXIMUM_ALLOWED,
1240 if (!NT_STATUS_IS_OK(status)) {
1244 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1246 SEC_FLAG_MAXIMUM_ALLOWED,
1249 if (!NT_STATUS_IS_OK(status)) {
1253 /* Create domain user */
1255 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1256 strlower_m(acct_name);
1258 init_lsa_String(&lsa_acct_name, acct_name);
1260 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1267 if (!NT_STATUS_IS_OK(status)) {
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;
1278 user_rid = user_rids.ids[0];
1280 /* Open handle on user */
1282 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1284 SEC_FLAG_MAXIMUM_ALLOWED,
1287 if (!NT_STATUS_IS_OK(status)) {
1293 status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1297 if (!NT_STATUS_IS_OK(status)) {
1298 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1302 /* now disable and setuser info */
1304 info->info16.acct_flags |= ACB_DISABLED;
1306 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1311 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1315 if (is_valid_policy_hnd(&domain_pol)) {
1316 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1318 if (is_valid_policy_hnd(&sam_pol)) {
1319 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1321 TALLOC_FREE(pipe_hnd);
1331 /****************************************************************
1332 ****************************************************************/
1334 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1337 struct smbconf_ctx *ctx;
1339 werr = smbconf_init_reg(r, &ctx, NULL);
1340 if (!W_ERROR_IS_OK(werr)) {
1344 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1346 werr = smbconf_set_global_parameter(ctx, "security", "user");
1347 W_ERROR_NOT_OK_GOTO_DONE(werr);
1349 werr = smbconf_set_global_parameter(ctx, "workgroup",
1352 smbconf_delete_global_parameter(ctx, "realm");
1356 werr = smbconf_set_global_parameter(ctx, "security", "domain");
1357 W_ERROR_NOT_OK_GOTO_DONE(werr);
1359 werr = smbconf_set_global_parameter(ctx, "workgroup",
1360 r->out.netbios_domain_name);
1361 W_ERROR_NOT_OK_GOTO_DONE(werr);
1363 if (r->out.domain_is_ad) {
1364 werr = smbconf_set_global_parameter(ctx, "security", "ads");
1365 W_ERROR_NOT_OK_GOTO_DONE(werr);
1367 werr = smbconf_set_global_parameter(ctx, "realm",
1368 r->out.dns_domain_name);
1369 W_ERROR_NOT_OK_GOTO_DONE(werr);
1373 smbconf_shutdown(ctx);
1377 /****************************************************************
1378 ****************************************************************/
1380 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1382 WERROR werr = WERR_OK;
1383 struct smbconf_ctx *ctx;
1385 werr = smbconf_init_reg(r, &ctx, NULL);
1386 if (!W_ERROR_IS_OK(werr)) {
1390 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1392 werr = smbconf_set_global_parameter(ctx, "security", "user");
1393 W_ERROR_NOT_OK_GOTO_DONE(werr);
1395 werr = smbconf_delete_global_parameter(ctx, "workgroup");
1396 W_ERROR_NOT_OK_GOTO_DONE(werr);
1398 smbconf_delete_global_parameter(ctx, "realm");
1402 smbconf_shutdown(ctx);
1406 /****************************************************************
1407 ****************************************************************/
1409 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1413 if (!W_ERROR_IS_OK(r->out.result)) {
1414 return r->out.result;
1417 if (!r->in.modify_config) {
1421 werr = do_join_modify_vals_config(r);
1422 if (!W_ERROR_IS_OK(werr)) {
1426 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1428 r->out.modified_config = true;
1429 r->out.result = werr;
1434 /****************************************************************
1435 ****************************************************************/
1437 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1441 if (!W_ERROR_IS_OK(r->out.result)) {
1442 return r->out.result;
1445 if (!r->in.modify_config) {
1449 werr = do_unjoin_modify_vals_config(r);
1450 if (!W_ERROR_IS_OK(werr)) {
1454 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1456 r->out.modified_config = true;
1457 r->out.result = werr;
1462 /****************************************************************
1463 ****************************************************************/
1465 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1466 const char *domain_str,
1467 const char **domain_p,
1470 char *domain = NULL;
1472 const char *p = NULL;
1474 if (!domain_str || !domain_p || !dc_p) {
1478 p = strchr_m(domain_str, '\\');
1481 domain = talloc_strndup(mem_ctx, domain_str,
1482 PTR_DIFF(p, domain_str));
1483 dc = talloc_strdup(mem_ctx, p+1);
1488 domain = talloc_strdup(mem_ctx, domain_str);
1504 /****************************************************************
1505 ****************************************************************/
1507 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1508 struct libnet_JoinCtx *r)
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;
1516 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1519 libnet_join_set_error_string(mem_ctx, r,
1520 "Failed to parse domain name");
1521 return WERR_INVALID_PARAM;
1525 return WERR_SETUP_DOMAIN_CONTROLLER;
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;
1537 /****************************************************************
1538 ****************************************************************/
1540 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
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)));
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)));
1568 /****************************************************************
1569 ****************************************************************/
1571 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1572 struct libnet_JoinCtx *r)
1576 if (!W_ERROR_IS_OK(r->out.result)) {
1577 return r->out.result;
1580 werr = do_JoinConfig(r);
1581 if (!W_ERROR_IS_OK(werr)) {
1585 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
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);
1595 if (r->out.domain_is_ad &&
1596 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1597 ADS_STATUS ads_status;
1599 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1600 if (!ADS_ERR_OK(ads_status)) {
1601 return WERR_GENERAL_FAILURE;
1604 #endif /* WITH_ADS */
1606 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1611 /****************************************************************
1612 ****************************************************************/
1614 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1616 const char *krb5_cc_env = NULL;
1619 ads_destroy(&r->in.ads);
1622 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1623 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1624 unsetenv(KRB5_ENV_CCNAME);
1630 /****************************************************************
1631 ****************************************************************/
1633 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1635 const char *krb5_cc_env = NULL;
1638 ads_destroy(&r->in.ads);
1641 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1642 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1643 unsetenv(KRB5_ENV_CCNAME);
1649 /****************************************************************
1650 ****************************************************************/
1652 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1653 struct libnet_JoinCtx **r)
1655 struct libnet_JoinCtx *ctx;
1656 const char *krb5_cc_env = NULL;
1658 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1663 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1665 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1666 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
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);
1675 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1682 /****************************************************************
1683 ****************************************************************/
1685 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1686 struct libnet_UnjoinCtx **r)
1688 struct libnet_UnjoinCtx *ctx;
1689 const char *krb5_cc_env = NULL;
1691 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1696 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1698 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1699 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
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);
1713 /****************************************************************
1714 ****************************************************************/
1716 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
1717 struct libnet_JoinCtx *r)
1719 bool valid_security = false;
1720 bool valid_workgroup = false;
1721 bool valid_realm = false;
1723 /* check if configuration is already set correctly */
1725 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
1727 switch (r->out.domain_is_ad) {
1729 valid_security = (lp_security() == SEC_DOMAIN);
1730 if (valid_workgroup && valid_security) {
1731 /* nothing to be done */
1736 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
1737 switch (lp_security()) {
1740 valid_security = true;
1743 if (valid_workgroup && valid_realm && valid_security) {
1744 /* nothing to be done */
1750 /* check if we are supposed to manipulate configuration */
1752 if (!r->in.modify_config) {
1754 char *wrong_conf = talloc_strdup(mem_ctx, "");
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);
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);
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;
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);
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;
1791 /* check if we are able to manipulate configuration */
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;
1803 /****************************************************************
1804 ****************************************************************/
1806 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1807 struct libnet_JoinCtx *r)
1811 struct cli_state *cli = NULL;
1813 ADS_STATUS ads_status;
1814 #endif /* WITH_ADS */
1816 if (!r->in.dc_name) {
1817 struct netr_DsRGetDCNameInfo *info;
1819 status = dsgetdcname(mem_ctx,
1824 DS_FORCE_REDISCOVERY |
1825 DS_DIRECTORY_SERVICE_REQUIRED |
1826 DS_WRITABLE_REQUIRED |
1829 if (!NT_STATUS_IS_OK(status)) {
1830 libnet_join_set_error_string(mem_ctx, r,
1831 "failed to find DC for domain %s",
1833 get_friendly_nt_error_msg(status));
1834 return WERR_DCNOTFOUND;
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);
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);
1850 werr = libnet_join_check_config(mem_ctx, r);
1851 if (!W_ERROR_IS_OK(werr)) {
1856 if (r->out.domain_is_ad && r->in.account_ou &&
1857 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1859 ads_status = libnet_join_connect_ads(mem_ctx, r);
1860 if (!ADS_ERR_OK(ads_status)) {
1861 return WERR_DEFAULT_JOIN_REQUIRED;
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",
1869 ads_errstr(ads_status));
1870 return WERR_DEFAULT_JOIN_REQUIRED;
1873 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1875 #endif /* WITH_ADS */
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);
1881 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
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;
1890 werr = ntstatus_to_werror(status);
1894 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1895 werr = WERR_SETUP_NOT_JOINED;
1909 /****************************************************************
1910 ****************************************************************/
1912 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
1913 struct libnet_JoinCtx *r)
1916 struct libnet_UnjoinCtx *u = NULL;
1918 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
1919 if (!W_ERROR_IS_OK(werr)) {
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;
1932 werr = libnet_Unjoin(mem_ctx, u);
1938 /****************************************************************
1939 ****************************************************************/
1941 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1942 struct libnet_JoinCtx *r)
1947 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
1950 werr = libnet_join_pre_processing(mem_ctx, r);
1951 if (!W_ERROR_IS_OK(werr)) {
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)) {
1962 werr = libnet_join_post_processing(mem_ctx, r);
1963 if (!W_ERROR_IS_OK(werr)) {
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);
1975 r->out.result = werr;
1978 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
1983 /****************************************************************
1984 ****************************************************************/
1986 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1987 struct libnet_UnjoinCtx *r)
1991 if (!r->in.domain_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;
1998 r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid);
1999 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
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);
2008 if (!r->in.dc_name) {
2009 struct netr_DsRGetDCNameInfo *info;
2011 status = dsgetdcname(mem_ctx,
2016 DS_DIRECTORY_SERVICE_REQUIRED |
2017 DS_WRITABLE_REQUIRED |
2020 if (!NT_STATUS_IS_OK(status)) {
2021 libnet_unjoin_set_error_string(mem_ctx, r,
2022 "failed to find DC for domain %s",
2024 get_friendly_nt_error_msg(status));
2025 return WERR_DCNOTFOUND;
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);
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
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)) {
2043 r->out.dns_domain_name =
2044 talloc_strdup(mem_ctx,
2045 r->in.ads->server.realm);
2047 libnet_unjoin_remove_machine_acct(mem_ctx, r);
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));
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);
2060 #endif /* WITH_ADS */
2062 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
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;
2073 return ntstatus_to_werror(status);
2076 r->out.disabled_machine_account = true;
2079 /* If disable succeeded or was not requested at all, we
2080 should be getting rid of our end of things */
2082 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2087 /****************************************************************
2088 ****************************************************************/
2090 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2091 struct libnet_UnjoinCtx *r)
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;
2099 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2102 libnet_unjoin_set_error_string(mem_ctx, r,
2103 "Failed to parse domain name");
2104 return WERR_INVALID_PARAM;
2108 return WERR_SETUP_DOMAIN_CONTROLLER;
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;
2120 /****************************************************************
2121 ****************************************************************/
2123 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2124 struct libnet_UnjoinCtx *r)
2126 saf_delete(r->out.netbios_domain_name);
2127 saf_delete(r->out.dns_domain_name);
2129 return libnet_unjoin_config(r);
2132 /****************************************************************
2133 ****************************************************************/
2135 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2136 struct libnet_UnjoinCtx *r)
2141 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2144 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2145 if (!W_ERROR_IS_OK(werr)) {
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);
2157 werr = libnet_unjoin_post_processing(mem_ctx, r);
2158 if (!W_ERROR_IS_OK(werr)) {
2163 r->out.result = werr;
2166 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);