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/>.
23 #include "librpc/gen_ndr/ndr_libnet_join.h"
24 #include "libnet/libnet_join.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/cli_samr.h"
27 #include "rpc_client/init_samr.h"
28 #include "../librpc/gen_ndr/cli_lsa.h"
29 #include "rpc_client/cli_lsarpc.h"
30 #include "../librpc/gen_ndr/cli_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
32 #include "lib/smbconf/smbconf.h"
33 #include "lib/smbconf/smbconf_reg.h"
34 #include "../libds/common/flags.h"
36 #include "rpc_client/init_lsa.h"
38 /****************************************************************
39 ****************************************************************/
41 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
44 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
45 DEBUG(1,("libnet_Join:\n%s", str)); \
49 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
50 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
51 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
52 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
54 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
57 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
58 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
62 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
63 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
64 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
65 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
67 /****************************************************************
68 ****************************************************************/
70 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
71 struct libnet_JoinCtx *r,
72 const char *format, ...)
76 if (r->out.error_string) {
80 va_start(args, format);
81 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
85 /****************************************************************
86 ****************************************************************/
88 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
89 struct libnet_UnjoinCtx *r,
90 const char *format, ...)
94 if (r->out.error_string) {
98 va_start(args, format);
99 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
105 /****************************************************************
106 ****************************************************************/
108 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
109 const char *netbios_domain_name,
111 const char *user_name,
112 const char *password,
116 ADS_STRUCT *my_ads = NULL;
119 my_ads = ads_init(dns_domain_name,
123 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
127 SAFE_FREE(my_ads->auth.user_name);
128 my_ads->auth.user_name = SMB_STRDUP(user_name);
129 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
131 SAFE_FREE(my_ads->auth.realm);
132 my_ads->auth.realm = smb_xstrdup(cp);
133 strupper_m(my_ads->auth.realm);
138 SAFE_FREE(my_ads->auth.password);
139 my_ads->auth.password = SMB_STRDUP(password);
142 status = ads_connect_user_creds(my_ads);
143 if (!ADS_ERR_OK(status)) {
144 ads_destroy(&my_ads);
152 /****************************************************************
153 ****************************************************************/
155 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
156 struct libnet_JoinCtx *r)
160 status = libnet_connect_ads(r->out.dns_domain_name,
161 r->out.netbios_domain_name,
164 r->in.admin_password,
166 if (!ADS_ERR_OK(status)) {
167 libnet_join_set_error_string(mem_ctx, r,
168 "failed to connect to AD: %s",
173 if (!r->out.netbios_domain_name) {
174 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
175 r->in.ads->server.workgroup);
176 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
179 if (!r->out.dns_domain_name) {
180 r->out.dns_domain_name = talloc_strdup(mem_ctx,
181 r->in.ads->config.realm);
182 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
185 r->out.domain_is_ad = true;
190 /****************************************************************
191 ****************************************************************/
193 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
194 struct libnet_UnjoinCtx *r)
198 status = libnet_connect_ads(r->in.domain_name,
202 r->in.admin_password,
204 if (!ADS_ERR_OK(status)) {
205 libnet_unjoin_set_error_string(mem_ctx, r,
206 "failed to connect to AD: %s",
213 /****************************************************************
214 join a domain using ADS (LDAP mods)
215 ****************************************************************/
217 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
218 struct libnet_JoinCtx *r)
221 LDAPMessage *res = NULL;
222 const char *attrs[] = { "dn", NULL };
225 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
226 if (!ADS_ERR_OK(status)) {
230 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
231 if (!ADS_ERR_OK(status)) {
235 if (ads_count_replies(r->in.ads, res) != 1) {
236 ads_msgfree(r->in.ads, res);
237 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
240 ads_msgfree(r->in.ads, res);
242 /* Attempt to create the machine account and bail if this fails.
243 Assume that the admin wants exactly what they requested */
245 status = ads_create_machine_acct(r->in.ads,
249 if (ADS_ERR_OK(status)) {
250 DEBUG(1,("machine account creation created\n"));
252 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
253 (status.err.rc == LDAP_ALREADY_EXISTS)) {
254 status = ADS_SUCCESS;
257 if (!ADS_ERR_OK(status)) {
258 DEBUG(1,("machine account creation failed\n"));
262 status = ads_move_machine_acct(r->in.ads,
266 if (!ADS_ERR_OK(status)) {
267 DEBUG(1,("failure to locate/move pre-existing "
268 "machine account\n"));
272 DEBUG(1,("The machine account %s the specified OU.\n",
273 moved ? "was moved into" : "already exists in"));
278 /****************************************************************
279 ****************************************************************/
281 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
282 struct libnet_UnjoinCtx *r)
287 status = libnet_unjoin_connect_ads(mem_ctx, r);
288 if (!ADS_ERR_OK(status)) {
289 libnet_unjoin_set_error_string(mem_ctx, r,
290 "failed to connect to AD: %s",
296 status = ads_leave_realm(r->in.ads, r->in.machine_name);
297 if (!ADS_ERR_OK(status)) {
298 libnet_unjoin_set_error_string(mem_ctx, r,
299 "failed to leave realm: %s",
307 /****************************************************************
308 ****************************************************************/
310 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
311 struct libnet_JoinCtx *r)
314 LDAPMessage *res = NULL;
317 if (!r->in.machine_name) {
318 return ADS_ERROR(LDAP_NO_MEMORY);
321 status = ads_find_machine_acct(r->in.ads,
324 if (!ADS_ERR_OK(status)) {
328 if (ads_count_replies(r->in.ads, res) != 1) {
329 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
333 dn = ads_get_dn(r->in.ads, mem_ctx, res);
335 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
339 r->out.dn = talloc_strdup(mem_ctx, dn);
341 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
346 ads_msgfree(r->in.ads, res);
352 /****************************************************************
353 Set a machines dNSHostName and servicePrincipalName attributes
354 ****************************************************************/
356 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
357 struct libnet_JoinCtx *r)
362 const char *spn_array[3] = {NULL, NULL, NULL};
367 status = libnet_join_find_machine_acct(mem_ctx, r);
368 if (!ADS_ERR_OK(status)) {
372 /* Windows only creates HOST/shortname & HOST/fqdn. */
374 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
376 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
381 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
382 || (strchr(my_fqdn, '.') == NULL)) {
383 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
384 r->out.dns_domain_name);
389 if (!strequal(my_fqdn, r->in.machine_name)) {
390 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
392 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
397 mods = ads_init_mods(mem_ctx);
399 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
402 /* fields of primary importance */
404 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
405 if (!ADS_ERR_OK(status)) {
406 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
409 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
411 if (!ADS_ERR_OK(status)) {
412 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
415 return ads_gen_mod(r->in.ads, r->out.dn, mods);
418 /****************************************************************
419 ****************************************************************/
421 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
422 struct libnet_JoinCtx *r)
427 if (!r->in.create_upn) {
433 status = libnet_join_find_machine_acct(mem_ctx, r);
434 if (!ADS_ERR_OK(status)) {
439 r->in.upn = talloc_asprintf(mem_ctx,
442 r->out.dns_domain_name);
444 return ADS_ERROR(LDAP_NO_MEMORY);
448 /* now do the mods */
450 mods = ads_init_mods(mem_ctx);
452 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
455 /* fields of primary importance */
457 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
458 if (!ADS_ERR_OK(status)) {
459 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
462 return ads_gen_mod(r->in.ads, r->out.dn, mods);
466 /****************************************************************
467 ****************************************************************/
469 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
470 struct libnet_JoinCtx *r)
476 if (!r->in.os_name || !r->in.os_version ) {
482 status = libnet_join_find_machine_acct(mem_ctx, r);
483 if (!ADS_ERR_OK(status)) {
487 /* now do the mods */
489 mods = ads_init_mods(mem_ctx);
491 return ADS_ERROR(LDAP_NO_MEMORY);
494 os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
496 return ADS_ERROR(LDAP_NO_MEMORY);
499 /* fields of primary importance */
501 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
503 if (!ADS_ERR_OK(status)) {
507 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
509 if (!ADS_ERR_OK(status)) {
513 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
515 if (!ADS_ERR_OK(status)) {
519 return ads_gen_mod(r->in.ads, r->out.dn, mods);
522 /****************************************************************
523 ****************************************************************/
525 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
526 struct libnet_JoinCtx *r)
528 if (!USE_SYSTEM_KEYTAB) {
532 if (ads_keytab_create_default(r->in.ads) != 0) {
539 /****************************************************************
540 ****************************************************************/
542 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
543 struct libnet_JoinCtx *r)
545 uint32_t domain_func;
547 const char *salt = NULL;
548 char *std_salt = NULL;
550 status = ads_domain_func_level(r->in.ads, &domain_func);
551 if (!ADS_ERR_OK(status)) {
552 libnet_join_set_error_string(mem_ctx, r,
553 "failed to determine domain functional level: %s",
558 /* go ahead and setup the default salt */
560 std_salt = kerberos_standard_des_salt();
562 libnet_join_set_error_string(mem_ctx, r,
563 "failed to obtain standard DES salt");
567 salt = talloc_strdup(mem_ctx, std_salt);
574 /* if it's a Windows functional domain, we have to look for the UPN */
576 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
579 upn = ads_get_upn(r->in.ads, mem_ctx,
582 salt = talloc_strdup(mem_ctx, upn);
589 return kerberos_secrets_store_des_salt(salt);
592 /****************************************************************
593 ****************************************************************/
595 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
596 struct libnet_JoinCtx *r)
601 status = libnet_join_connect_ads(mem_ctx, r);
602 if (!ADS_ERR_OK(status)) {
607 status = libnet_join_set_machine_spn(mem_ctx, r);
608 if (!ADS_ERR_OK(status)) {
609 libnet_join_set_error_string(mem_ctx, r,
610 "failed to set machine spn: %s",
615 status = libnet_join_set_os_attributes(mem_ctx, r);
616 if (!ADS_ERR_OK(status)) {
617 libnet_join_set_error_string(mem_ctx, r,
618 "failed to set machine os attributes: %s",
623 status = libnet_join_set_machine_upn(mem_ctx, r);
624 if (!ADS_ERR_OK(status)) {
625 libnet_join_set_error_string(mem_ctx, r,
626 "failed to set machine upn: %s",
631 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
632 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
635 if (!libnet_join_create_keytab(mem_ctx, r)) {
636 libnet_join_set_error_string(mem_ctx, r,
637 "failed to create kerberos keytab");
638 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
643 #endif /* WITH_ADS */
645 /****************************************************************
646 Store the machine password and domain SID
647 ****************************************************************/
649 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
650 struct libnet_JoinCtx *r)
652 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
655 DEBUG(1,("Failed to save domain sid\n"));
659 if (!secrets_store_machine_password(r->in.machine_password,
660 r->out.netbios_domain_name,
661 r->in.secure_channel_type))
663 DEBUG(1,("Failed to save machine password\n"));
670 /****************************************************************
671 Connect dc's IPC$ share
672 ****************************************************************/
674 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
678 struct cli_state **cli)
683 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
686 if (use_kerberos && pass) {
687 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
690 return cli_full_connection(cli, NULL,
701 /****************************************************************
702 Lookup domain dc's info
703 ****************************************************************/
705 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
706 struct libnet_JoinCtx *r,
707 struct cli_state **cli)
709 struct rpc_pipe_client *pipe_hnd = NULL;
710 struct policy_handle lsa_pol;
711 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
712 union lsa_PolicyInformation *info = NULL;
714 status = libnet_join_connect_dc_ipc(r->in.dc_name,
716 r->in.admin_password,
719 if (!NT_STATUS_IS_OK(status)) {
723 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
725 if (!NT_STATUS_IS_OK(status)) {
726 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
731 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
732 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
733 if (!NT_STATUS_IS_OK(status)) {
737 status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx,
741 if (NT_STATUS_IS_OK(status)) {
742 r->out.domain_is_ad = true;
743 r->out.netbios_domain_name = info->dns.name.string;
744 r->out.dns_domain_name = info->dns.dns_domain.string;
745 r->out.forest_name = info->dns.dns_forest.string;
746 r->out.domain_sid = sid_dup_talloc(mem_ctx, info->dns.sid);
747 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
750 if (!NT_STATUS_IS_OK(status)) {
751 status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
753 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
755 if (!NT_STATUS_IS_OK(status)) {
759 r->out.netbios_domain_name = info->account_domain.name.string;
760 r->out.domain_sid = sid_dup_talloc(mem_ctx, info->account_domain.sid);
761 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
764 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
765 TALLOC_FREE(pipe_hnd);
771 /****************************************************************
772 Do the domain join unsecure
773 ****************************************************************/
775 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
776 struct libnet_JoinCtx *r,
777 struct cli_state *cli)
779 struct rpc_pipe_client *pipe_hnd = NULL;
780 unsigned char orig_trust_passwd_hash[16];
781 unsigned char new_trust_passwd_hash[16];
782 fstring trust_passwd;
785 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
787 if (!NT_STATUS_IS_OK(status)) {
791 if (!r->in.machine_password) {
792 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
793 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
796 E_md4hash(r->in.machine_password, new_trust_passwd_hash);
798 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
799 fstrcpy(trust_passwd, r->in.admin_password);
800 strlower_m(trust_passwd);
803 * Machine names can be 15 characters, but the max length on
804 * a password is 14. --jerry
807 trust_passwd[14] = '\0';
809 E_md4hash(trust_passwd, orig_trust_passwd_hash);
811 status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx,
813 orig_trust_passwd_hash,
814 r->in.machine_password,
815 new_trust_passwd_hash,
816 r->in.secure_channel_type);
821 /****************************************************************
823 ****************************************************************/
825 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
826 struct libnet_JoinCtx *r,
827 struct cli_state *cli)
829 struct rpc_pipe_client *pipe_hnd = NULL;
830 struct policy_handle sam_pol, domain_pol, user_pol;
831 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
833 struct lsa_String lsa_acct_name;
835 uint32_t acct_flags = ACB_WSTRUST;
836 struct samr_Ids user_rids;
837 struct samr_Ids name_types;
838 union samr_UserInfo user_info;
840 struct samr_CryptPassword crypt_pwd;
841 struct samr_CryptPasswordEx crypt_pwd_ex;
843 ZERO_STRUCT(sam_pol);
844 ZERO_STRUCT(domain_pol);
845 ZERO_STRUCT(user_pol);
847 switch (r->in.secure_channel_type) {
849 acct_flags = ACB_WSTRUST;
852 acct_flags = ACB_SVRTRUST;
855 return NT_STATUS_INVALID_PARAMETER;
858 if (!r->in.machine_password) {
859 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
860 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
863 /* Open the domain */
865 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
867 if (!NT_STATUS_IS_OK(status)) {
868 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
873 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
875 SAMR_ACCESS_ENUM_DOMAINS
876 | SAMR_ACCESS_LOOKUP_DOMAIN,
878 if (!NT_STATUS_IS_OK(status)) {
882 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
884 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
885 | SAMR_DOMAIN_ACCESS_CREATE_USER
886 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
889 if (!NT_STATUS_IS_OK(status)) {
893 /* Create domain user */
895 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
896 strlower_m(acct_name);
898 init_lsa_String(&lsa_acct_name, acct_name);
900 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
901 uint32_t access_desired =
902 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
903 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
904 SAMR_USER_ACCESS_SET_PASSWORD |
905 SAMR_USER_ACCESS_GET_ATTRIBUTES |
906 SAMR_USER_ACCESS_SET_ATTRIBUTES;
907 uint32_t access_granted = 0;
909 DEBUG(10,("Creating account with desired access mask: %d\n",
912 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
920 if (!NT_STATUS_IS_OK(status) &&
921 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
923 DEBUG(10,("Creation of workstation account failed: %s\n",
926 /* If NT_STATUS_ACCESS_DENIED then we have a valid
927 username/password combo but the user does not have
928 administrator access. */
930 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
931 libnet_join_set_error_string(mem_ctx, r,
932 "User specified does not have "
933 "administrator privileges");
939 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
940 if (!(r->in.join_flags &
941 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
946 /* We *must* do this.... don't ask... */
948 if (NT_STATUS_IS_OK(status)) {
949 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
953 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
959 if (!NT_STATUS_IS_OK(status)) {
963 if (name_types.ids[0] != SID_NAME_USER) {
964 DEBUG(0,("%s is not a user account (type=%d)\n",
965 acct_name, name_types.ids[0]));
966 status = NT_STATUS_INVALID_WORKSTATION;
970 user_rid = user_rids.ids[0];
972 /* Open handle on user */
974 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
976 SEC_FLAG_MAXIMUM_ALLOWED,
979 if (!NT_STATUS_IS_OK(status)) {
983 /* Fill in the additional account flags now */
985 acct_flags |= ACB_PWNOEXP;
987 /* Set account flags on machine account */
988 ZERO_STRUCT(user_info.info16);
989 user_info.info16.acct_flags = acct_flags;
991 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
996 if (!NT_STATUS_IS_OK(status)) {
998 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
1001 libnet_join_set_error_string(mem_ctx, r,
1002 "Failed to set account flags for machine account (%s)\n",
1007 /* Set password on machine account - first try level 26 */
1009 init_samr_CryptPasswordEx(r->in.machine_password,
1010 &cli->user_session_key,
1013 user_info.info26.password = crypt_pwd_ex;
1014 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1016 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1021 if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
1023 /* retry with level 24 */
1025 init_samr_CryptPassword(r->in.machine_password,
1026 &cli->user_session_key,
1029 user_info.info24.password = crypt_pwd;
1030 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1032 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1038 if (!NT_STATUS_IS_OK(status)) {
1040 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
1043 libnet_join_set_error_string(mem_ctx, r,
1044 "Failed to set password for machine account (%s)\n",
1049 status = NT_STATUS_OK;
1056 if (is_valid_policy_hnd(&sam_pol)) {
1057 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1059 if (is_valid_policy_hnd(&domain_pol)) {
1060 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1062 if (is_valid_policy_hnd(&user_pol)) {
1063 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1065 TALLOC_FREE(pipe_hnd);
1070 /****************************************************************
1071 ****************************************************************/
1073 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
1074 const char *machine_name,
1075 const char *dc_name)
1077 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
1078 struct cli_state *cli = NULL;
1079 struct rpc_pipe_client *pipe_hnd = NULL;
1080 struct rpc_pipe_client *netlogon_pipe = NULL;
1082 char *machine_password = NULL;
1083 char *machine_account = NULL;
1086 return NT_STATUS_INVALID_PARAMETER;
1089 if (!secrets_init()) {
1090 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1093 machine_password = secrets_fetch_machine_password(netbios_domain_name,
1095 if (!machine_password) {
1096 return NT_STATUS_NO_TRUST_LSA_SECRET;
1099 if (asprintf(&machine_account, "%s$", machine_name) == -1) {
1100 SAFE_FREE(machine_password);
1101 return NT_STATUS_NO_MEMORY;
1104 status = cli_full_connection(&cli, NULL,
1113 free(machine_account);
1114 free(machine_password);
1116 if (!NT_STATUS_IS_OK(status)) {
1117 status = cli_full_connection(&cli, NULL,
1128 if (!NT_STATUS_IS_OK(status)) {
1132 status = get_schannel_session_key(cli, netbios_domain_name,
1133 &neg_flags, &netlogon_pipe);
1134 if (!NT_STATUS_IS_OK(status)) {
1135 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
1137 return NT_STATUS_OK;
1140 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1141 "key from server %s for domain %s. Error was %s\n",
1142 cli->desthost, netbios_domain_name, nt_errstr(status)));
1147 if (!lp_client_schannel()) {
1149 return NT_STATUS_OK;
1152 status = cli_rpc_pipe_open_schannel_with_key(
1153 cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
1154 DCERPC_AUTH_LEVEL_PRIVACY,
1155 netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd);
1159 if (!NT_STATUS_IS_OK(status)) {
1160 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1161 "on netlogon pipe to server %s for domain %s. "
1163 cli->desthost, netbios_domain_name, nt_errstr(status)));
1167 return NT_STATUS_OK;
1170 /****************************************************************
1171 ****************************************************************/
1173 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1174 struct libnet_JoinCtx *r)
1178 status = libnet_join_ok(r->out.netbios_domain_name,
1181 if (!NT_STATUS_IS_OK(status)) {
1182 libnet_join_set_error_string(mem_ctx, r,
1183 "failed to verify domain membership after joining: %s",
1184 get_friendly_nt_error_msg(status));
1185 return WERR_SETUP_NOT_JOINED;
1191 /****************************************************************
1192 ****************************************************************/
1194 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1195 struct libnet_UnjoinCtx *r)
1197 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1201 if (!secrets_delete_domain_sid(lp_workgroup())) {
1208 /****************************************************************
1209 ****************************************************************/
1211 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1212 struct libnet_UnjoinCtx *r)
1214 struct cli_state *cli = NULL;
1215 struct rpc_pipe_client *pipe_hnd = NULL;
1216 struct policy_handle sam_pol, domain_pol, user_pol;
1217 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1220 struct lsa_String lsa_acct_name;
1221 struct samr_Ids user_rids;
1222 struct samr_Ids name_types;
1223 union samr_UserInfo *info = NULL;
1225 ZERO_STRUCT(sam_pol);
1226 ZERO_STRUCT(domain_pol);
1227 ZERO_STRUCT(user_pol);
1229 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1230 r->in.admin_account,
1231 r->in.admin_password,
1234 if (!NT_STATUS_IS_OK(status)) {
1238 /* Open the domain */
1240 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
1242 if (!NT_STATUS_IS_OK(status)) {
1243 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1244 nt_errstr(status)));
1248 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1250 SEC_FLAG_MAXIMUM_ALLOWED,
1252 if (!NT_STATUS_IS_OK(status)) {
1256 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1258 SEC_FLAG_MAXIMUM_ALLOWED,
1261 if (!NT_STATUS_IS_OK(status)) {
1265 /* Create domain user */
1267 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1268 strlower_m(acct_name);
1270 init_lsa_String(&lsa_acct_name, acct_name);
1272 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1279 if (!NT_STATUS_IS_OK(status)) {
1283 if (name_types.ids[0] != SID_NAME_USER) {
1284 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1285 name_types.ids[0]));
1286 status = NT_STATUS_INVALID_WORKSTATION;
1290 user_rid = user_rids.ids[0];
1292 /* Open handle on user */
1294 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1296 SEC_FLAG_MAXIMUM_ALLOWED,
1299 if (!NT_STATUS_IS_OK(status)) {
1305 status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1309 if (!NT_STATUS_IS_OK(status)) {
1310 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1314 /* now disable and setuser info */
1316 info->info16.acct_flags |= ACB_DISABLED;
1318 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1323 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1327 if (is_valid_policy_hnd(&domain_pol)) {
1328 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1330 if (is_valid_policy_hnd(&sam_pol)) {
1331 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1333 TALLOC_FREE(pipe_hnd);
1343 /****************************************************************
1344 ****************************************************************/
1346 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1349 struct smbconf_ctx *ctx;
1351 werr = smbconf_init_reg(r, &ctx, NULL);
1352 if (!W_ERROR_IS_OK(werr)) {
1356 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1358 werr = smbconf_set_global_parameter(ctx, "security", "user");
1359 W_ERROR_NOT_OK_GOTO_DONE(werr);
1361 werr = smbconf_set_global_parameter(ctx, "workgroup",
1364 smbconf_delete_global_parameter(ctx, "realm");
1368 werr = smbconf_set_global_parameter(ctx, "security", "domain");
1369 W_ERROR_NOT_OK_GOTO_DONE(werr);
1371 werr = smbconf_set_global_parameter(ctx, "workgroup",
1372 r->out.netbios_domain_name);
1373 W_ERROR_NOT_OK_GOTO_DONE(werr);
1375 if (r->out.domain_is_ad) {
1376 werr = smbconf_set_global_parameter(ctx, "security", "ads");
1377 W_ERROR_NOT_OK_GOTO_DONE(werr);
1379 werr = smbconf_set_global_parameter(ctx, "realm",
1380 r->out.dns_domain_name);
1381 W_ERROR_NOT_OK_GOTO_DONE(werr);
1385 smbconf_shutdown(ctx);
1389 /****************************************************************
1390 ****************************************************************/
1392 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1394 WERROR werr = WERR_OK;
1395 struct smbconf_ctx *ctx;
1397 werr = smbconf_init_reg(r, &ctx, NULL);
1398 if (!W_ERROR_IS_OK(werr)) {
1402 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1404 werr = smbconf_set_global_parameter(ctx, "security", "user");
1405 W_ERROR_NOT_OK_GOTO_DONE(werr);
1407 werr = smbconf_delete_global_parameter(ctx, "workgroup");
1408 W_ERROR_NOT_OK_GOTO_DONE(werr);
1410 smbconf_delete_global_parameter(ctx, "realm");
1414 smbconf_shutdown(ctx);
1418 /****************************************************************
1419 ****************************************************************/
1421 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1425 if (!W_ERROR_IS_OK(r->out.result)) {
1426 return r->out.result;
1429 if (!r->in.modify_config) {
1433 werr = do_join_modify_vals_config(r);
1434 if (!W_ERROR_IS_OK(werr)) {
1438 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1440 r->out.modified_config = true;
1441 r->out.result = werr;
1446 /****************************************************************
1447 ****************************************************************/
1449 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1453 if (!W_ERROR_IS_OK(r->out.result)) {
1454 return r->out.result;
1457 if (!r->in.modify_config) {
1461 werr = do_unjoin_modify_vals_config(r);
1462 if (!W_ERROR_IS_OK(werr)) {
1466 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1468 r->out.modified_config = true;
1469 r->out.result = werr;
1474 /****************************************************************
1475 ****************************************************************/
1477 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1478 const char *domain_str,
1479 const char **domain_p,
1482 char *domain = NULL;
1484 const char *p = NULL;
1486 if (!domain_str || !domain_p || !dc_p) {
1490 p = strchr_m(domain_str, '\\');
1493 domain = talloc_strndup(mem_ctx, domain_str,
1494 PTR_DIFF(p, domain_str));
1495 dc = talloc_strdup(mem_ctx, p+1);
1500 domain = talloc_strdup(mem_ctx, domain_str);
1516 /****************************************************************
1517 ****************************************************************/
1519 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1520 struct libnet_JoinCtx *r)
1522 if (!r->in.domain_name) {
1523 libnet_join_set_error_string(mem_ctx, r,
1524 "No domain name defined");
1525 return WERR_INVALID_PARAM;
1528 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1531 libnet_join_set_error_string(mem_ctx, r,
1532 "Failed to parse domain name");
1533 return WERR_INVALID_PARAM;
1537 return WERR_SETUP_DOMAIN_CONTROLLER;
1540 if (!secrets_init()) {
1541 libnet_join_set_error_string(mem_ctx, r,
1542 "Unable to open secrets database");
1543 return WERR_CAN_NOT_COMPLETE;
1549 /****************************************************************
1550 ****************************************************************/
1552 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1556 /* Try adding dom admins to builtin\admins. Only log failures. */
1557 status = create_builtin_administrators(domain_sid);
1558 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1559 DEBUG(10,("Unable to auto-add domain administrators to "
1560 "BUILTIN\\Administrators during join because "
1561 "winbindd must be running."));
1562 } else if (!NT_STATUS_IS_OK(status)) {
1563 DEBUG(5, ("Failed to auto-add domain administrators to "
1564 "BUILTIN\\Administrators during join: %s\n",
1565 nt_errstr(status)));
1568 /* Try adding dom users to builtin\users. Only log failures. */
1569 status = create_builtin_users(domain_sid);
1570 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1571 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1572 "during join because winbindd must be running."));
1573 } else if (!NT_STATUS_IS_OK(status)) {
1574 DEBUG(5, ("Failed to auto-add domain administrators to "
1575 "BUILTIN\\Administrators during join: %s\n",
1576 nt_errstr(status)));
1580 /****************************************************************
1581 ****************************************************************/
1583 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1584 struct libnet_JoinCtx *r)
1588 if (!W_ERROR_IS_OK(r->out.result)) {
1589 return r->out.result;
1592 werr = do_JoinConfig(r);
1593 if (!W_ERROR_IS_OK(werr)) {
1597 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1601 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1602 if (r->out.dns_domain_name) {
1603 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1607 if (r->out.domain_is_ad &&
1608 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1609 ADS_STATUS ads_status;
1611 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1612 if (!ADS_ERR_OK(ads_status)) {
1613 return WERR_GENERAL_FAILURE;
1616 #endif /* WITH_ADS */
1618 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1623 /****************************************************************
1624 ****************************************************************/
1626 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1628 const char *krb5_cc_env = NULL;
1631 ads_destroy(&r->in.ads);
1634 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1635 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1636 unsetenv(KRB5_ENV_CCNAME);
1642 /****************************************************************
1643 ****************************************************************/
1645 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1647 const char *krb5_cc_env = NULL;
1650 ads_destroy(&r->in.ads);
1653 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1654 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1655 unsetenv(KRB5_ENV_CCNAME);
1661 /****************************************************************
1662 ****************************************************************/
1664 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1665 struct libnet_JoinCtx **r)
1667 struct libnet_JoinCtx *ctx;
1668 const char *krb5_cc_env = NULL;
1670 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1675 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1677 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1678 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1680 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1681 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1682 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1683 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1684 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1687 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1694 /****************************************************************
1695 ****************************************************************/
1697 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1698 struct libnet_UnjoinCtx **r)
1700 struct libnet_UnjoinCtx *ctx;
1701 const char *krb5_cc_env = NULL;
1703 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1708 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1710 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1711 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1713 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1714 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1715 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1716 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1717 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1725 /****************************************************************
1726 ****************************************************************/
1728 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
1729 struct libnet_JoinCtx *r)
1731 bool valid_security = false;
1732 bool valid_workgroup = false;
1733 bool valid_realm = false;
1735 /* check if configuration is already set correctly */
1737 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
1739 switch (r->out.domain_is_ad) {
1741 valid_security = (lp_security() == SEC_DOMAIN);
1742 if (valid_workgroup && valid_security) {
1743 /* nothing to be done */
1748 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
1749 switch (lp_security()) {
1752 valid_security = true;
1755 if (valid_workgroup && valid_realm && valid_security) {
1756 /* nothing to be done */
1762 /* check if we are supposed to manipulate configuration */
1764 if (!r->in.modify_config) {
1766 char *wrong_conf = talloc_strdup(mem_ctx, "");
1768 if (!valid_workgroup) {
1769 wrong_conf = talloc_asprintf_append(wrong_conf,
1770 "\"workgroup\" set to '%s', should be '%s'",
1771 lp_workgroup(), r->out.netbios_domain_name);
1772 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1776 wrong_conf = talloc_asprintf_append(wrong_conf,
1777 "\"realm\" set to '%s', should be '%s'",
1778 lp_realm(), r->out.dns_domain_name);
1779 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1782 if (!valid_security) {
1783 const char *sec = NULL;
1784 switch (lp_security()) {
1785 case SEC_SHARE: sec = "share"; break;
1786 case SEC_USER: sec = "user"; break;
1787 case SEC_DOMAIN: sec = "domain"; break;
1788 case SEC_ADS: sec = "ads"; break;
1790 wrong_conf = talloc_asprintf_append(wrong_conf,
1791 "\"security\" set to '%s', should be %s",
1792 sec, r->out.domain_is_ad ?
1793 "either 'domain' or 'ads'" : "'domain'");
1794 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1797 libnet_join_set_error_string(mem_ctx, r,
1798 "Invalid configuration (%s) and configuration modification "
1799 "was not requested", wrong_conf);
1800 return WERR_CAN_NOT_COMPLETE;
1803 /* check if we are able to manipulate configuration */
1805 if (!lp_config_backend_is_registry()) {
1806 libnet_join_set_error_string(mem_ctx, r,
1807 "Configuration manipulation requested but not "
1808 "supported by backend");
1809 return WERR_NOT_SUPPORTED;
1815 /****************************************************************
1816 ****************************************************************/
1818 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1819 struct libnet_JoinCtx *r)
1823 struct cli_state *cli = NULL;
1825 ADS_STATUS ads_status;
1826 #endif /* WITH_ADS */
1828 if (!r->in.dc_name) {
1829 struct netr_DsRGetDCNameInfo *info;
1831 status = dsgetdcname(mem_ctx,
1836 DS_FORCE_REDISCOVERY |
1837 DS_DIRECTORY_SERVICE_REQUIRED |
1838 DS_WRITABLE_REQUIRED |
1841 if (!NT_STATUS_IS_OK(status)) {
1842 libnet_join_set_error_string(mem_ctx, r,
1843 "failed to find DC for domain %s",
1845 get_friendly_nt_error_msg(status));
1846 return WERR_DCNOTFOUND;
1849 dc = strip_hostname(info->dc_unc);
1850 r->in.dc_name = talloc_strdup(mem_ctx, dc);
1851 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1854 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
1855 if (!NT_STATUS_IS_OK(status)) {
1856 libnet_join_set_error_string(mem_ctx, r,
1857 "failed to lookup DC info for domain '%s' over rpc: %s",
1858 r->in.domain_name, get_friendly_nt_error_msg(status));
1859 return ntstatus_to_werror(status);
1862 werr = libnet_join_check_config(mem_ctx, r);
1863 if (!W_ERROR_IS_OK(werr)) {
1868 if (r->out.domain_is_ad && r->in.account_ou &&
1869 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1871 ads_status = libnet_join_connect_ads(mem_ctx, r);
1872 if (!ADS_ERR_OK(ads_status)) {
1873 return WERR_DEFAULT_JOIN_REQUIRED;
1876 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1877 if (!ADS_ERR_OK(ads_status)) {
1878 libnet_join_set_error_string(mem_ctx, r,
1879 "failed to precreate account in ou %s: %s",
1881 ads_errstr(ads_status));
1882 return WERR_DEFAULT_JOIN_REQUIRED;
1885 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1887 #endif /* WITH_ADS */
1889 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
1890 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
1891 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
1893 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
1895 if (!NT_STATUS_IS_OK(status)) {
1896 libnet_join_set_error_string(mem_ctx, r,
1897 "failed to join domain '%s' over rpc: %s",
1898 r->in.domain_name, get_friendly_nt_error_msg(status));
1899 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1900 return WERR_SETUP_ALREADY_JOINED;
1902 werr = ntstatus_to_werror(status);
1906 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1907 werr = WERR_SETUP_NOT_JOINED;
1921 /****************************************************************
1922 ****************************************************************/
1924 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
1925 struct libnet_JoinCtx *r)
1928 struct libnet_UnjoinCtx *u = NULL;
1930 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
1931 if (!W_ERROR_IS_OK(werr)) {
1935 u->in.debug = r->in.debug;
1936 u->in.dc_name = r->in.dc_name;
1937 u->in.domain_name = r->in.domain_name;
1938 u->in.admin_account = r->in.admin_account;
1939 u->in.admin_password = r->in.admin_password;
1940 u->in.modify_config = r->in.modify_config;
1941 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1942 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1944 werr = libnet_Unjoin(mem_ctx, u);
1950 /****************************************************************
1951 ****************************************************************/
1953 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1954 struct libnet_JoinCtx *r)
1959 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
1962 werr = libnet_join_pre_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_DomainJoin(mem_ctx, r);
1969 if (!W_ERROR_IS_OK(werr)) {
1974 werr = libnet_join_post_processing(mem_ctx, r);
1975 if (!W_ERROR_IS_OK(werr)) {
1979 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1980 werr = libnet_join_post_verify(mem_ctx, r);
1981 if (!W_ERROR_IS_OK(werr)) {
1982 libnet_join_rollback(mem_ctx, r);
1987 r->out.result = werr;
1990 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
1995 /****************************************************************
1996 ****************************************************************/
1998 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1999 struct libnet_UnjoinCtx *r)
2003 if (!r->in.domain_sid) {
2005 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2006 libnet_unjoin_set_error_string(mem_ctx, r,
2007 "Unable to fetch domain sid: are we joined?");
2008 return WERR_SETUP_NOT_JOINED;
2010 r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid);
2011 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2014 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2015 !r->in.delete_machine_account) {
2016 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2020 if (!r->in.dc_name) {
2021 struct netr_DsRGetDCNameInfo *info;
2023 status = dsgetdcname(mem_ctx,
2028 DS_DIRECTORY_SERVICE_REQUIRED |
2029 DS_WRITABLE_REQUIRED |
2032 if (!NT_STATUS_IS_OK(status)) {
2033 libnet_unjoin_set_error_string(mem_ctx, r,
2034 "failed to find DC for domain %s",
2036 get_friendly_nt_error_msg(status));
2037 return WERR_DCNOTFOUND;
2040 dc = strip_hostname(info->dc_unc);
2041 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2042 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2046 /* for net ads leave, try to delete the account. If it works,
2047 no sense in disabling. If it fails, we can still try to
2050 if (r->in.delete_machine_account) {
2051 ADS_STATUS ads_status;
2052 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2053 if (ADS_ERR_OK(ads_status)) {
2055 r->out.dns_domain_name =
2056 talloc_strdup(mem_ctx,
2057 r->in.ads->server.realm);
2059 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2061 if (!ADS_ERR_OK(ads_status)) {
2062 libnet_unjoin_set_error_string(mem_ctx, r,
2063 "failed to remove machine account from AD: %s",
2064 ads_errstr(ads_status));
2066 r->out.deleted_machine_account = true;
2067 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2068 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2072 #endif /* WITH_ADS */
2074 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2076 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2077 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2078 if (!NT_STATUS_IS_OK(status)) {
2079 libnet_unjoin_set_error_string(mem_ctx, r,
2080 "failed to disable machine account via rpc: %s",
2081 get_friendly_nt_error_msg(status));
2082 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2083 return WERR_SETUP_NOT_JOINED;
2085 return ntstatus_to_werror(status);
2088 r->out.disabled_machine_account = true;
2091 /* If disable succeeded or was not requested at all, we
2092 should be getting rid of our end of things */
2094 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2099 /****************************************************************
2100 ****************************************************************/
2102 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2103 struct libnet_UnjoinCtx *r)
2105 if (!r->in.domain_name) {
2106 libnet_unjoin_set_error_string(mem_ctx, r,
2107 "No domain name defined");
2108 return WERR_INVALID_PARAM;
2111 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2114 libnet_unjoin_set_error_string(mem_ctx, r,
2115 "Failed to parse domain name");
2116 return WERR_INVALID_PARAM;
2120 return WERR_SETUP_DOMAIN_CONTROLLER;
2123 if (!secrets_init()) {
2124 libnet_unjoin_set_error_string(mem_ctx, r,
2125 "Unable to open secrets database");
2126 return WERR_CAN_NOT_COMPLETE;
2132 /****************************************************************
2133 ****************************************************************/
2135 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2136 struct libnet_UnjoinCtx *r)
2138 saf_delete(r->out.netbios_domain_name);
2139 saf_delete(r->out.dns_domain_name);
2141 return libnet_unjoin_config(r);
2144 /****************************************************************
2145 ****************************************************************/
2147 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2148 struct libnet_UnjoinCtx *r)
2153 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2156 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2157 if (!W_ERROR_IS_OK(werr)) {
2161 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2162 werr = libnet_DomainUnjoin(mem_ctx, r);
2163 if (!W_ERROR_IS_OK(werr)) {
2164 libnet_unjoin_config(r);
2169 werr = libnet_unjoin_post_processing(mem_ctx, r);
2170 if (!W_ERROR_IS_OK(werr)) {
2175 r->out.result = werr;
2178 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);