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 "rpc_client/init_samr.h"
26 #include "../librpc/gen_ndr/cli_lsa.h"
27 #include "rpc_client/cli_lsarpc.h"
28 #include "../librpc/gen_ndr/cli_netlogon.h"
29 #include "rpc_client/cli_netlogon.h"
30 #include "lib/smbconf/smbconf.h"
31 #include "lib/smbconf/smbconf_reg.h"
33 /****************************************************************
34 ****************************************************************/
36 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
39 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
40 DEBUG(1,("libnet_Join:\n%s", str)); \
44 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
45 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
46 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
47 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
49 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
52 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
53 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
57 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
58 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
59 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
60 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
62 /****************************************************************
63 ****************************************************************/
65 static void libnet_join_set_error_string(TALLOC_CTX
*mem_ctx
,
66 struct libnet_JoinCtx
*r
,
67 const char *format
, ...)
71 if (r
->out
.error_string
) {
75 va_start(args
, format
);
76 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
80 /****************************************************************
81 ****************************************************************/
83 static void libnet_unjoin_set_error_string(TALLOC_CTX
*mem_ctx
,
84 struct libnet_UnjoinCtx
*r
,
85 const char *format
, ...)
89 if (r
->out
.error_string
) {
93 va_start(args
, format
);
94 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
100 /****************************************************************
101 ****************************************************************/
103 static ADS_STATUS
libnet_connect_ads(const char *dns_domain_name
,
104 const char *netbios_domain_name
,
106 const char *user_name
,
107 const char *password
,
111 ADS_STRUCT
*my_ads
= NULL
;
113 my_ads
= ads_init(dns_domain_name
,
117 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
121 SAFE_FREE(my_ads
->auth
.user_name
);
122 my_ads
->auth
.user_name
= SMB_STRDUP(user_name
);
126 SAFE_FREE(my_ads
->auth
.password
);
127 my_ads
->auth
.password
= SMB_STRDUP(password
);
130 status
= ads_connect_user_creds(my_ads
);
131 if (!ADS_ERR_OK(status
)) {
132 ads_destroy(&my_ads
);
140 /****************************************************************
141 ****************************************************************/
143 static ADS_STATUS
libnet_join_connect_ads(TALLOC_CTX
*mem_ctx
,
144 struct libnet_JoinCtx
*r
)
148 status
= libnet_connect_ads(r
->out
.dns_domain_name
,
149 r
->out
.netbios_domain_name
,
152 r
->in
.admin_password
,
154 if (!ADS_ERR_OK(status
)) {
155 libnet_join_set_error_string(mem_ctx
, r
,
156 "failed to connect to AD: %s",
161 if (!r
->out
.netbios_domain_name
) {
162 r
->out
.netbios_domain_name
= talloc_strdup(mem_ctx
,
163 r
->in
.ads
->server
.workgroup
);
164 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.netbios_domain_name
);
167 if (!r
->out
.dns_domain_name
) {
168 r
->out
.dns_domain_name
= talloc_strdup(mem_ctx
,
169 r
->in
.ads
->config
.realm
);
170 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
173 r
->out
.domain_is_ad
= true;
178 /****************************************************************
179 ****************************************************************/
181 static ADS_STATUS
libnet_unjoin_connect_ads(TALLOC_CTX
*mem_ctx
,
182 struct libnet_UnjoinCtx
*r
)
186 status
= libnet_connect_ads(r
->in
.domain_name
,
190 r
->in
.admin_password
,
192 if (!ADS_ERR_OK(status
)) {
193 libnet_unjoin_set_error_string(mem_ctx
, r
,
194 "failed to connect to AD: %s",
201 /****************************************************************
202 join a domain using ADS (LDAP mods)
203 ****************************************************************/
205 static ADS_STATUS
libnet_join_precreate_machine_acct(TALLOC_CTX
*mem_ctx
,
206 struct libnet_JoinCtx
*r
)
209 LDAPMessage
*res
= NULL
;
210 const char *attrs
[] = { "dn", NULL
};
213 status
= ads_check_ou_dn(mem_ctx
, r
->in
.ads
, &r
->in
.account_ou
);
214 if (!ADS_ERR_OK(status
)) {
218 status
= ads_search_dn(r
->in
.ads
, &res
, r
->in
.account_ou
, attrs
);
219 if (!ADS_ERR_OK(status
)) {
223 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
224 ads_msgfree(r
->in
.ads
, res
);
225 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT
);
228 ads_msgfree(r
->in
.ads
, res
);
230 /* Attempt to create the machine account and bail if this fails.
231 Assume that the admin wants exactly what they requested */
233 status
= ads_create_machine_acct(r
->in
.ads
,
237 if (ADS_ERR_OK(status
)) {
238 DEBUG(1,("machine account creation created\n"));
240 } else if ((status
.error_type
== ENUM_ADS_ERROR_LDAP
) &&
241 (status
.err
.rc
== LDAP_ALREADY_EXISTS
)) {
242 status
= ADS_SUCCESS
;
245 if (!ADS_ERR_OK(status
)) {
246 DEBUG(1,("machine account creation failed\n"));
250 status
= ads_move_machine_acct(r
->in
.ads
,
254 if (!ADS_ERR_OK(status
)) {
255 DEBUG(1,("failure to locate/move pre-existing "
256 "machine account\n"));
260 DEBUG(1,("The machine account %s the specified OU.\n",
261 moved
? "was moved into" : "already exists in"));
266 /****************************************************************
267 ****************************************************************/
269 static ADS_STATUS
libnet_unjoin_remove_machine_acct(TALLOC_CTX
*mem_ctx
,
270 struct libnet_UnjoinCtx
*r
)
275 status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
276 if (!ADS_ERR_OK(status
)) {
277 libnet_unjoin_set_error_string(mem_ctx
, r
,
278 "failed to connect to AD: %s",
284 status
= ads_leave_realm(r
->in
.ads
, r
->in
.machine_name
);
285 if (!ADS_ERR_OK(status
)) {
286 libnet_unjoin_set_error_string(mem_ctx
, r
,
287 "failed to leave realm: %s",
295 /****************************************************************
296 ****************************************************************/
298 static ADS_STATUS
libnet_join_find_machine_acct(TALLOC_CTX
*mem_ctx
,
299 struct libnet_JoinCtx
*r
)
302 LDAPMessage
*res
= NULL
;
305 if (!r
->in
.machine_name
) {
306 return ADS_ERROR(LDAP_NO_MEMORY
);
309 status
= ads_find_machine_acct(r
->in
.ads
,
312 if (!ADS_ERR_OK(status
)) {
316 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
317 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
321 dn
= ads_get_dn(r
->in
.ads
, mem_ctx
, res
);
323 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
327 r
->out
.dn
= talloc_strdup(mem_ctx
, dn
);
329 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
334 ads_msgfree(r
->in
.ads
, res
);
340 /****************************************************************
341 Set a machines dNSHostName and servicePrincipalName attributes
342 ****************************************************************/
344 static ADS_STATUS
libnet_join_set_machine_spn(TALLOC_CTX
*mem_ctx
,
345 struct libnet_JoinCtx
*r
)
350 const char *spn_array
[3] = {NULL
, NULL
, NULL
};
355 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
356 if (!ADS_ERR_OK(status
)) {
360 /* Windows only creates HOST/shortname & HOST/fqdn. */
362 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", r
->in
.machine_name
);
364 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
369 if (!name_to_fqdn(my_fqdn
, r
->in
.machine_name
)
370 || (strchr(my_fqdn
, '.') == NULL
)) {
371 fstr_sprintf(my_fqdn
, "%s.%s", r
->in
.machine_name
,
372 r
->out
.dns_domain_name
);
377 if (!strequal(my_fqdn
, r
->in
.machine_name
)) {
378 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", my_fqdn
);
380 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
385 mods
= ads_init_mods(mem_ctx
);
387 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
390 /* fields of primary importance */
392 status
= ads_mod_str(mem_ctx
, &mods
, "dNSHostName", my_fqdn
);
393 if (!ADS_ERR_OK(status
)) {
394 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
397 status
= ads_mod_strlist(mem_ctx
, &mods
, "servicePrincipalName",
399 if (!ADS_ERR_OK(status
)) {
400 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
403 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
406 /****************************************************************
407 ****************************************************************/
409 static ADS_STATUS
libnet_join_set_machine_upn(TALLOC_CTX
*mem_ctx
,
410 struct libnet_JoinCtx
*r
)
415 if (!r
->in
.create_upn
) {
421 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
422 if (!ADS_ERR_OK(status
)) {
427 r
->in
.upn
= talloc_asprintf(mem_ctx
,
430 r
->out
.dns_domain_name
);
432 return ADS_ERROR(LDAP_NO_MEMORY
);
436 /* now do the mods */
438 mods
= ads_init_mods(mem_ctx
);
440 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
443 /* fields of primary importance */
445 status
= ads_mod_str(mem_ctx
, &mods
, "userPrincipalName", r
->in
.upn
);
446 if (!ADS_ERR_OK(status
)) {
447 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
450 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
454 /****************************************************************
455 ****************************************************************/
457 static ADS_STATUS
libnet_join_set_os_attributes(TALLOC_CTX
*mem_ctx
,
458 struct libnet_JoinCtx
*r
)
464 if (!r
->in
.os_name
|| !r
->in
.os_version
) {
470 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
471 if (!ADS_ERR_OK(status
)) {
475 /* now do the mods */
477 mods
= ads_init_mods(mem_ctx
);
479 return ADS_ERROR(LDAP_NO_MEMORY
);
482 os_sp
= talloc_asprintf(mem_ctx
, "Samba %s", samba_version_string());
484 return ADS_ERROR(LDAP_NO_MEMORY
);
487 /* fields of primary importance */
489 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystem",
491 if (!ADS_ERR_OK(status
)) {
495 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemVersion",
497 if (!ADS_ERR_OK(status
)) {
501 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemServicePack",
503 if (!ADS_ERR_OK(status
)) {
507 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
510 /****************************************************************
511 ****************************************************************/
513 static bool libnet_join_create_keytab(TALLOC_CTX
*mem_ctx
,
514 struct libnet_JoinCtx
*r
)
516 if (!USE_SYSTEM_KEYTAB
) {
520 if (ads_keytab_create_default(r
->in
.ads
) != 0) {
527 /****************************************************************
528 ****************************************************************/
530 static bool libnet_join_derive_salting_principal(TALLOC_CTX
*mem_ctx
,
531 struct libnet_JoinCtx
*r
)
533 uint32_t domain_func
;
535 const char *salt
= NULL
;
536 char *std_salt
= NULL
;
538 status
= ads_domain_func_level(r
->in
.ads
, &domain_func
);
539 if (!ADS_ERR_OK(status
)) {
540 libnet_join_set_error_string(mem_ctx
, r
,
541 "failed to determine domain functional level: %s",
546 /* go ahead and setup the default salt */
548 std_salt
= kerberos_standard_des_salt();
550 libnet_join_set_error_string(mem_ctx
, r
,
551 "failed to obtain standard DES salt");
555 salt
= talloc_strdup(mem_ctx
, std_salt
);
562 /* if it's a Windows functional domain, we have to look for the UPN */
564 if (domain_func
== DS_DOMAIN_FUNCTION_2000
) {
567 upn
= ads_get_upn(r
->in
.ads
, mem_ctx
,
570 salt
= talloc_strdup(mem_ctx
, upn
);
577 return kerberos_secrets_store_des_salt(salt
);
580 /****************************************************************
581 ****************************************************************/
583 static ADS_STATUS
libnet_join_post_processing_ads(TALLOC_CTX
*mem_ctx
,
584 struct libnet_JoinCtx
*r
)
589 status
= libnet_join_connect_ads(mem_ctx
, r
);
590 if (!ADS_ERR_OK(status
)) {
595 status
= libnet_join_set_machine_spn(mem_ctx
, r
);
596 if (!ADS_ERR_OK(status
)) {
597 libnet_join_set_error_string(mem_ctx
, r
,
598 "failed to set machine spn: %s",
603 status
= libnet_join_set_os_attributes(mem_ctx
, r
);
604 if (!ADS_ERR_OK(status
)) {
605 libnet_join_set_error_string(mem_ctx
, r
,
606 "failed to set machine os attributes: %s",
611 status
= libnet_join_set_machine_upn(mem_ctx
, r
);
612 if (!ADS_ERR_OK(status
)) {
613 libnet_join_set_error_string(mem_ctx
, r
,
614 "failed to set machine upn: %s",
619 if (!libnet_join_derive_salting_principal(mem_ctx
, r
)) {
620 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
623 if (!libnet_join_create_keytab(mem_ctx
, r
)) {
624 libnet_join_set_error_string(mem_ctx
, r
,
625 "failed to create kerberos keytab");
626 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
631 #endif /* WITH_ADS */
633 /****************************************************************
634 Store the machine password and domain SID
635 ****************************************************************/
637 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX
*mem_ctx
,
638 struct libnet_JoinCtx
*r
)
640 if (!secrets_store_domain_sid(r
->out
.netbios_domain_name
,
643 DEBUG(1,("Failed to save domain sid\n"));
647 if (!secrets_store_machine_password(r
->in
.machine_password
,
648 r
->out
.netbios_domain_name
,
649 r
->in
.secure_channel_type
))
651 DEBUG(1,("Failed to save machine password\n"));
658 /****************************************************************
659 Connect dc's IPC$ share
660 ****************************************************************/
662 static NTSTATUS
libnet_join_connect_dc_ipc(const char *dc
,
666 struct cli_state
**cli
)
671 flags
|= CLI_FULL_CONNECTION_USE_KERBEROS
;
674 if (use_kerberos
&& pass
) {
675 flags
|= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS
;
678 return cli_full_connection(cli
, NULL
,
689 /****************************************************************
690 Lookup domain dc's info
691 ****************************************************************/
693 static NTSTATUS
libnet_join_lookup_dc_rpc(TALLOC_CTX
*mem_ctx
,
694 struct libnet_JoinCtx
*r
,
695 struct cli_state
**cli
)
697 struct rpc_pipe_client
*pipe_hnd
= NULL
;
698 struct policy_handle lsa_pol
;
699 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
700 union lsa_PolicyInformation
*info
= NULL
;
702 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
704 r
->in
.admin_password
,
707 if (!NT_STATUS_IS_OK(status
)) {
711 status
= cli_rpc_pipe_open_noauth(*cli
, &ndr_table_lsarpc
.syntax_id
,
713 if (!NT_STATUS_IS_OK(status
)) {
714 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
719 status
= rpccli_lsa_open_policy(pipe_hnd
, mem_ctx
, true,
720 SEC_FLAG_MAXIMUM_ALLOWED
, &lsa_pol
);
721 if (!NT_STATUS_IS_OK(status
)) {
725 status
= rpccli_lsa_QueryInfoPolicy2(pipe_hnd
, mem_ctx
,
729 if (NT_STATUS_IS_OK(status
)) {
730 r
->out
.domain_is_ad
= true;
731 r
->out
.netbios_domain_name
= info
->dns
.name
.string
;
732 r
->out
.dns_domain_name
= info
->dns
.dns_domain
.string
;
733 r
->out
.forest_name
= info
->dns
.dns_forest
.string
;
734 r
->out
.domain_sid
= sid_dup_talloc(mem_ctx
, info
->dns
.sid
);
735 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
738 if (!NT_STATUS_IS_OK(status
)) {
739 status
= rpccli_lsa_QueryInfoPolicy(pipe_hnd
, mem_ctx
,
741 LSA_POLICY_INFO_ACCOUNT_DOMAIN
,
743 if (!NT_STATUS_IS_OK(status
)) {
747 r
->out
.netbios_domain_name
= info
->account_domain
.name
.string
;
748 r
->out
.domain_sid
= sid_dup_talloc(mem_ctx
, info
->account_domain
.sid
);
749 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
752 rpccli_lsa_Close(pipe_hnd
, mem_ctx
, &lsa_pol
);
753 TALLOC_FREE(pipe_hnd
);
759 /****************************************************************
760 Do the domain join unsecure
761 ****************************************************************/
763 static NTSTATUS
libnet_join_joindomain_rpc_unsecure(TALLOC_CTX
*mem_ctx
,
764 struct libnet_JoinCtx
*r
,
765 struct cli_state
*cli
)
767 struct rpc_pipe_client
*pipe_hnd
= NULL
;
768 unsigned char orig_trust_passwd_hash
[16];
769 unsigned char new_trust_passwd_hash
[16];
770 fstring trust_passwd
;
773 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_netlogon
.syntax_id
,
775 if (!NT_STATUS_IS_OK(status
)) {
779 if (!r
->in
.machine_password
) {
780 r
->in
.machine_password
= generate_random_str(mem_ctx
, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
781 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
784 E_md4hash(r
->in
.machine_password
, new_trust_passwd_hash
);
786 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
787 fstrcpy(trust_passwd
, r
->in
.admin_password
);
788 strlower_m(trust_passwd
);
791 * Machine names can be 15 characters, but the max length on
792 * a password is 14. --jerry
795 trust_passwd
[14] = '\0';
797 E_md4hash(trust_passwd
, orig_trust_passwd_hash
);
799 status
= rpccli_netlogon_set_trust_password(pipe_hnd
, mem_ctx
,
801 orig_trust_passwd_hash
,
802 r
->in
.machine_password
,
803 new_trust_passwd_hash
,
804 r
->in
.secure_channel_type
);
809 /****************************************************************
811 ****************************************************************/
813 static NTSTATUS
libnet_join_joindomain_rpc(TALLOC_CTX
*mem_ctx
,
814 struct libnet_JoinCtx
*r
,
815 struct cli_state
*cli
)
817 struct rpc_pipe_client
*pipe_hnd
= NULL
;
818 struct policy_handle sam_pol
, domain_pol
, user_pol
;
819 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
821 struct lsa_String lsa_acct_name
;
823 uint32_t acct_flags
= ACB_WSTRUST
;
824 struct samr_Ids user_rids
;
825 struct samr_Ids name_types
;
826 union samr_UserInfo user_info
;
828 struct samr_CryptPassword crypt_pwd
;
829 struct samr_CryptPasswordEx crypt_pwd_ex
;
831 ZERO_STRUCT(sam_pol
);
832 ZERO_STRUCT(domain_pol
);
833 ZERO_STRUCT(user_pol
);
835 switch (r
->in
.secure_channel_type
) {
837 acct_flags
= ACB_WSTRUST
;
840 acct_flags
= ACB_SVRTRUST
;
843 return NT_STATUS_INVALID_PARAMETER
;
846 if (!r
->in
.machine_password
) {
847 r
->in
.machine_password
= generate_random_str(mem_ctx
, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
848 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
851 /* Open the domain */
853 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
855 if (!NT_STATUS_IS_OK(status
)) {
856 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
861 status
= rpccli_samr_Connect2(pipe_hnd
, mem_ctx
,
863 SAMR_ACCESS_ENUM_DOMAINS
864 | SAMR_ACCESS_LOOKUP_DOMAIN
,
866 if (!NT_STATUS_IS_OK(status
)) {
870 status
= rpccli_samr_OpenDomain(pipe_hnd
, mem_ctx
,
872 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
873 | SAMR_DOMAIN_ACCESS_CREATE_USER
874 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT
,
877 if (!NT_STATUS_IS_OK(status
)) {
881 /* Create domain user */
883 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
884 strlower_m(acct_name
);
886 init_lsa_String(&lsa_acct_name
, acct_name
);
888 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
) {
889 uint32_t access_desired
=
890 SEC_GENERIC_READ
| SEC_GENERIC_WRITE
| SEC_GENERIC_EXECUTE
|
891 SEC_STD_WRITE_DAC
| SEC_STD_DELETE
|
892 SAMR_USER_ACCESS_SET_PASSWORD
|
893 SAMR_USER_ACCESS_GET_ATTRIBUTES
|
894 SAMR_USER_ACCESS_SET_ATTRIBUTES
;
895 uint32_t access_granted
= 0;
897 DEBUG(10,("Creating account with desired access mask: %d\n",
900 status
= rpccli_samr_CreateUser2(pipe_hnd
, mem_ctx
,
908 if (!NT_STATUS_IS_OK(status
) &&
909 !NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
911 DEBUG(10,("Creation of workstation account failed: %s\n",
914 /* If NT_STATUS_ACCESS_DENIED then we have a valid
915 username/password combo but the user does not have
916 administrator access. */
918 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
919 libnet_join_set_error_string(mem_ctx
, r
,
920 "User specified does not have "
921 "administrator privileges");
927 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
928 if (!(r
->in
.join_flags
&
929 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
)) {
934 /* We *must* do this.... don't ask... */
936 if (NT_STATUS_IS_OK(status
)) {
937 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
941 status
= rpccli_samr_LookupNames(pipe_hnd
, mem_ctx
,
947 if (!NT_STATUS_IS_OK(status
)) {
951 if (name_types
.ids
[0] != SID_NAME_USER
) {
952 DEBUG(0,("%s is not a user account (type=%d)\n",
953 acct_name
, name_types
.ids
[0]));
954 status
= NT_STATUS_INVALID_WORKSTATION
;
958 user_rid
= user_rids
.ids
[0];
960 /* Open handle on user */
962 status
= rpccli_samr_OpenUser(pipe_hnd
, mem_ctx
,
964 SEC_FLAG_MAXIMUM_ALLOWED
,
967 if (!NT_STATUS_IS_OK(status
)) {
971 /* Fill in the additional account flags now */
973 acct_flags
|= ACB_PWNOEXP
;
974 if (r
->out
.domain_is_ad
) {
975 #if !defined(ENCTYPE_ARCFOUR_HMAC)
976 acct_flags
|= ACB_USE_DES_KEY_ONLY
;
981 /* Set account flags on machine account */
982 ZERO_STRUCT(user_info
.info16
);
983 user_info
.info16
.acct_flags
= acct_flags
;
985 status
= rpccli_samr_SetUserInfo(pipe_hnd
, mem_ctx
,
990 if (!NT_STATUS_IS_OK(status
)) {
992 rpccli_samr_DeleteUser(pipe_hnd
, mem_ctx
,
995 libnet_join_set_error_string(mem_ctx
, r
,
996 "Failed to set account flags for machine account (%s)\n",
1001 /* Set password on machine account - first try level 26 */
1003 init_samr_CryptPasswordEx(r
->in
.machine_password
,
1004 &cli
->user_session_key
,
1007 user_info
.info26
.password
= crypt_pwd_ex
;
1008 user_info
.info26
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1010 status
= rpccli_samr_SetUserInfo2(pipe_hnd
, mem_ctx
,
1015 if (NT_STATUS_EQUAL(status
, NT_STATUS(DCERPC_FAULT_INVALID_TAG
))) {
1017 /* retry with level 24 */
1019 init_samr_CryptPassword(r
->in
.machine_password
,
1020 &cli
->user_session_key
,
1023 user_info
.info24
.password
= crypt_pwd
;
1024 user_info
.info24
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1026 status
= rpccli_samr_SetUserInfo2(pipe_hnd
, mem_ctx
,
1032 if (!NT_STATUS_IS_OK(status
)) {
1034 rpccli_samr_DeleteUser(pipe_hnd
, mem_ctx
,
1037 libnet_join_set_error_string(mem_ctx
, r
,
1038 "Failed to set password for machine account (%s)\n",
1043 status
= NT_STATUS_OK
;
1050 if (is_valid_policy_hnd(&sam_pol
)) {
1051 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &sam_pol
);
1053 if (is_valid_policy_hnd(&domain_pol
)) {
1054 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &domain_pol
);
1056 if (is_valid_policy_hnd(&user_pol
)) {
1057 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1059 TALLOC_FREE(pipe_hnd
);
1064 /****************************************************************
1065 ****************************************************************/
1067 NTSTATUS
libnet_join_ok(const char *netbios_domain_name
,
1068 const char *machine_name
,
1069 const char *dc_name
)
1071 uint32_t neg_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
1072 struct cli_state
*cli
= NULL
;
1073 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1074 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1076 char *machine_password
= NULL
;
1077 char *machine_account
= NULL
;
1080 return NT_STATUS_INVALID_PARAMETER
;
1083 if (!secrets_init()) {
1084 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1087 machine_password
= secrets_fetch_machine_password(netbios_domain_name
,
1089 if (!machine_password
) {
1090 return NT_STATUS_NO_TRUST_LSA_SECRET
;
1093 if (asprintf(&machine_account
, "%s$", machine_name
) == -1) {
1094 SAFE_FREE(machine_password
);
1095 return NT_STATUS_NO_MEMORY
;
1098 status
= cli_full_connection(&cli
, NULL
,
1107 free(machine_account
);
1108 free(machine_password
);
1110 if (!NT_STATUS_IS_OK(status
)) {
1111 status
= cli_full_connection(&cli
, NULL
,
1122 if (!NT_STATUS_IS_OK(status
)) {
1126 status
= get_schannel_session_key(cli
, netbios_domain_name
,
1127 &neg_flags
, &netlogon_pipe
);
1128 if (!NT_STATUS_IS_OK(status
)) {
1129 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_NETWORK_RESPONSE
)) {
1131 return NT_STATUS_OK
;
1134 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1135 "key from server %s for domain %s. Error was %s\n",
1136 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1141 if (!lp_client_schannel()) {
1143 return NT_STATUS_OK
;
1146 status
= cli_rpc_pipe_open_schannel_with_key(
1147 cli
, &ndr_table_netlogon
.syntax_id
, NCACN_NP
,
1148 DCERPC_AUTH_LEVEL_PRIVACY
,
1149 netbios_domain_name
, &netlogon_pipe
->dc
, &pipe_hnd
);
1153 if (!NT_STATUS_IS_OK(status
)) {
1154 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1155 "on netlogon pipe to server %s for domain %s. "
1157 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1161 return NT_STATUS_OK
;
1164 /****************************************************************
1165 ****************************************************************/
1167 static WERROR
libnet_join_post_verify(TALLOC_CTX
*mem_ctx
,
1168 struct libnet_JoinCtx
*r
)
1172 status
= libnet_join_ok(r
->out
.netbios_domain_name
,
1175 if (!NT_STATUS_IS_OK(status
)) {
1176 libnet_join_set_error_string(mem_ctx
, r
,
1177 "failed to verify domain membership after joining: %s",
1178 get_friendly_nt_error_msg(status
));
1179 return WERR_SETUP_NOT_JOINED
;
1185 /****************************************************************
1186 ****************************************************************/
1188 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX
*mem_ctx
,
1189 struct libnet_UnjoinCtx
*r
)
1191 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1195 if (!secrets_delete_domain_sid(lp_workgroup())) {
1202 /****************************************************************
1203 ****************************************************************/
1205 static NTSTATUS
libnet_join_unjoindomain_rpc(TALLOC_CTX
*mem_ctx
,
1206 struct libnet_UnjoinCtx
*r
)
1208 struct cli_state
*cli
= NULL
;
1209 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1210 struct policy_handle sam_pol
, domain_pol
, user_pol
;
1211 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1214 struct lsa_String lsa_acct_name
;
1215 struct samr_Ids user_rids
;
1216 struct samr_Ids name_types
;
1217 union samr_UserInfo
*info
= NULL
;
1219 ZERO_STRUCT(sam_pol
);
1220 ZERO_STRUCT(domain_pol
);
1221 ZERO_STRUCT(user_pol
);
1223 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
1224 r
->in
.admin_account
,
1225 r
->in
.admin_password
,
1228 if (!NT_STATUS_IS_OK(status
)) {
1232 /* Open the domain */
1234 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
1236 if (!NT_STATUS_IS_OK(status
)) {
1237 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1238 nt_errstr(status
)));
1242 status
= rpccli_samr_Connect2(pipe_hnd
, mem_ctx
,
1244 SEC_FLAG_MAXIMUM_ALLOWED
,
1246 if (!NT_STATUS_IS_OK(status
)) {
1250 status
= rpccli_samr_OpenDomain(pipe_hnd
, mem_ctx
,
1252 SEC_FLAG_MAXIMUM_ALLOWED
,
1255 if (!NT_STATUS_IS_OK(status
)) {
1259 /* Create domain user */
1261 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
1262 strlower_m(acct_name
);
1264 init_lsa_String(&lsa_acct_name
, acct_name
);
1266 status
= rpccli_samr_LookupNames(pipe_hnd
, mem_ctx
,
1273 if (!NT_STATUS_IS_OK(status
)) {
1277 if (name_types
.ids
[0] != SID_NAME_USER
) {
1278 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name
,
1279 name_types
.ids
[0]));
1280 status
= NT_STATUS_INVALID_WORKSTATION
;
1284 user_rid
= user_rids
.ids
[0];
1286 /* Open handle on user */
1288 status
= rpccli_samr_OpenUser(pipe_hnd
, mem_ctx
,
1290 SEC_FLAG_MAXIMUM_ALLOWED
,
1293 if (!NT_STATUS_IS_OK(status
)) {
1299 status
= rpccli_samr_QueryUserInfo(pipe_hnd
, mem_ctx
,
1303 if (!NT_STATUS_IS_OK(status
)) {
1304 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1308 /* now disable and setuser info */
1310 info
->info16
.acct_flags
|= ACB_DISABLED
;
1312 status
= rpccli_samr_SetUserInfo(pipe_hnd
, mem_ctx
,
1317 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1321 if (is_valid_policy_hnd(&domain_pol
)) {
1322 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &domain_pol
);
1324 if (is_valid_policy_hnd(&sam_pol
)) {
1325 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &sam_pol
);
1327 TALLOC_FREE(pipe_hnd
);
1337 /****************************************************************
1338 ****************************************************************/
1340 static WERROR
do_join_modify_vals_config(struct libnet_JoinCtx
*r
)
1343 struct smbconf_ctx
*ctx
;
1345 werr
= smbconf_init_reg(r
, &ctx
, NULL
);
1346 if (!W_ERROR_IS_OK(werr
)) {
1350 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1352 werr
= smbconf_set_global_parameter(ctx
, "security", "user");
1353 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1355 werr
= smbconf_set_global_parameter(ctx
, "workgroup",
1358 smbconf_delete_global_parameter(ctx
, "realm");
1362 werr
= smbconf_set_global_parameter(ctx
, "security", "domain");
1363 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1365 werr
= smbconf_set_global_parameter(ctx
, "workgroup",
1366 r
->out
.netbios_domain_name
);
1367 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1369 if (r
->out
.domain_is_ad
) {
1370 werr
= smbconf_set_global_parameter(ctx
, "security", "ads");
1371 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1373 werr
= smbconf_set_global_parameter(ctx
, "realm",
1374 r
->out
.dns_domain_name
);
1375 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1379 smbconf_shutdown(ctx
);
1383 /****************************************************************
1384 ****************************************************************/
1386 static WERROR
do_unjoin_modify_vals_config(struct libnet_UnjoinCtx
*r
)
1388 WERROR werr
= WERR_OK
;
1389 struct smbconf_ctx
*ctx
;
1391 werr
= smbconf_init_reg(r
, &ctx
, NULL
);
1392 if (!W_ERROR_IS_OK(werr
)) {
1396 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1398 werr
= smbconf_set_global_parameter(ctx
, "security", "user");
1399 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1401 werr
= smbconf_delete_global_parameter(ctx
, "workgroup");
1402 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1404 smbconf_delete_global_parameter(ctx
, "realm");
1408 smbconf_shutdown(ctx
);
1412 /****************************************************************
1413 ****************************************************************/
1415 static WERROR
do_JoinConfig(struct libnet_JoinCtx
*r
)
1419 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1420 return r
->out
.result
;
1423 if (!r
->in
.modify_config
) {
1427 werr
= do_join_modify_vals_config(r
);
1428 if (!W_ERROR_IS_OK(werr
)) {
1432 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1434 r
->out
.modified_config
= true;
1435 r
->out
.result
= werr
;
1440 /****************************************************************
1441 ****************************************************************/
1443 static WERROR
libnet_unjoin_config(struct libnet_UnjoinCtx
*r
)
1447 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1448 return r
->out
.result
;
1451 if (!r
->in
.modify_config
) {
1455 werr
= do_unjoin_modify_vals_config(r
);
1456 if (!W_ERROR_IS_OK(werr
)) {
1460 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1462 r
->out
.modified_config
= true;
1463 r
->out
.result
= werr
;
1468 /****************************************************************
1469 ****************************************************************/
1471 static bool libnet_parse_domain_dc(TALLOC_CTX
*mem_ctx
,
1472 const char *domain_str
,
1473 const char **domain_p
,
1476 char *domain
= NULL
;
1478 const char *p
= NULL
;
1480 if (!domain_str
|| !domain_p
|| !dc_p
) {
1484 p
= strchr_m(domain_str
, '\\');
1487 domain
= talloc_strndup(mem_ctx
, domain_str
,
1488 PTR_DIFF(p
, domain_str
));
1489 dc
= talloc_strdup(mem_ctx
, p
+1);
1494 domain
= talloc_strdup(mem_ctx
, domain_str
);
1510 /****************************************************************
1511 ****************************************************************/
1513 static WERROR
libnet_join_pre_processing(TALLOC_CTX
*mem_ctx
,
1514 struct libnet_JoinCtx
*r
)
1516 if (!r
->in
.domain_name
) {
1517 libnet_join_set_error_string(mem_ctx
, r
,
1518 "No domain name defined");
1519 return WERR_INVALID_PARAM
;
1522 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
1525 libnet_join_set_error_string(mem_ctx
, r
,
1526 "Failed to parse domain name");
1527 return WERR_INVALID_PARAM
;
1531 return WERR_SETUP_DOMAIN_CONTROLLER
;
1534 if (!secrets_init()) {
1535 libnet_join_set_error_string(mem_ctx
, r
,
1536 "Unable to open secrets database");
1537 return WERR_CAN_NOT_COMPLETE
;
1543 /****************************************************************
1544 ****************************************************************/
1546 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid
*domain_sid
)
1550 /* Try adding dom admins to builtin\admins. Only log failures. */
1551 status
= create_builtin_administrators(domain_sid
);
1552 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1553 DEBUG(10,("Unable to auto-add domain administrators to "
1554 "BUILTIN\\Administrators during join because "
1555 "winbindd must be running."));
1556 } else if (!NT_STATUS_IS_OK(status
)) {
1557 DEBUG(5, ("Failed to auto-add domain administrators to "
1558 "BUILTIN\\Administrators during join: %s\n",
1559 nt_errstr(status
)));
1562 /* Try adding dom users to builtin\users. Only log failures. */
1563 status
= create_builtin_users(domain_sid
);
1564 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1565 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1566 "during join because winbindd must be running."));
1567 } else if (!NT_STATUS_IS_OK(status
)) {
1568 DEBUG(5, ("Failed to auto-add domain administrators to "
1569 "BUILTIN\\Administrators during join: %s\n",
1570 nt_errstr(status
)));
1574 /****************************************************************
1575 ****************************************************************/
1577 static WERROR
libnet_join_post_processing(TALLOC_CTX
*mem_ctx
,
1578 struct libnet_JoinCtx
*r
)
1582 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1583 return r
->out
.result
;
1586 werr
= do_JoinConfig(r
);
1587 if (!W_ERROR_IS_OK(werr
)) {
1591 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1595 saf_join_store(r
->out
.netbios_domain_name
, r
->in
.dc_name
);
1596 if (r
->out
.dns_domain_name
) {
1597 saf_join_store(r
->out
.dns_domain_name
, r
->in
.dc_name
);
1601 if (r
->out
.domain_is_ad
&&
1602 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1603 ADS_STATUS ads_status
;
1605 ads_status
= libnet_join_post_processing_ads(mem_ctx
, r
);
1606 if (!ADS_ERR_OK(ads_status
)) {
1607 return WERR_GENERAL_FAILURE
;
1610 #endif /* WITH_ADS */
1612 libnet_join_add_dom_rids_to_builtins(r
->out
.domain_sid
);
1617 /****************************************************************
1618 ****************************************************************/
1620 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx
*r
)
1622 const char *krb5_cc_env
= NULL
;
1625 ads_destroy(&r
->in
.ads
);
1628 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1629 if (krb5_cc_env
&& StrCaseCmp(krb5_cc_env
, "MEMORY:libnetjoin")) {
1630 unsetenv(KRB5_ENV_CCNAME
);
1636 /****************************************************************
1637 ****************************************************************/
1639 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx
*r
)
1641 const char *krb5_cc_env
= NULL
;
1644 ads_destroy(&r
->in
.ads
);
1647 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1648 if (krb5_cc_env
&& StrCaseCmp(krb5_cc_env
, "MEMORY:libnetjoin")) {
1649 unsetenv(KRB5_ENV_CCNAME
);
1655 /****************************************************************
1656 ****************************************************************/
1658 WERROR
libnet_init_JoinCtx(TALLOC_CTX
*mem_ctx
,
1659 struct libnet_JoinCtx
**r
)
1661 struct libnet_JoinCtx
*ctx
;
1662 const char *krb5_cc_env
= NULL
;
1664 ctx
= talloc_zero(mem_ctx
, struct libnet_JoinCtx
);
1669 talloc_set_destructor(ctx
, libnet_destroy_JoinCtx
);
1671 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1672 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1674 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1675 if (!krb5_cc_env
|| (strlen(krb5_cc_env
) == 0)) {
1676 krb5_cc_env
= talloc_strdup(mem_ctx
, "MEMORY:libnetjoin");
1677 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env
);
1678 setenv(KRB5_ENV_CCNAME
, krb5_cc_env
, 1);
1681 ctx
->in
.secure_channel_type
= SEC_CHAN_WKSTA
;
1688 /****************************************************************
1689 ****************************************************************/
1691 WERROR
libnet_init_UnjoinCtx(TALLOC_CTX
*mem_ctx
,
1692 struct libnet_UnjoinCtx
**r
)
1694 struct libnet_UnjoinCtx
*ctx
;
1695 const char *krb5_cc_env
= NULL
;
1697 ctx
= talloc_zero(mem_ctx
, struct libnet_UnjoinCtx
);
1702 talloc_set_destructor(ctx
, libnet_destroy_UnjoinCtx
);
1704 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1705 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1707 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1708 if (!krb5_cc_env
|| (strlen(krb5_cc_env
) == 0)) {
1709 krb5_cc_env
= talloc_strdup(mem_ctx
, "MEMORY:libnetjoin");
1710 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env
);
1711 setenv(KRB5_ENV_CCNAME
, krb5_cc_env
, 1);
1719 /****************************************************************
1720 ****************************************************************/
1722 static WERROR
libnet_join_check_config(TALLOC_CTX
*mem_ctx
,
1723 struct libnet_JoinCtx
*r
)
1725 bool valid_security
= false;
1726 bool valid_workgroup
= false;
1727 bool valid_realm
= false;
1729 /* check if configuration is already set correctly */
1731 valid_workgroup
= strequal(lp_workgroup(), r
->out
.netbios_domain_name
);
1733 switch (r
->out
.domain_is_ad
) {
1735 valid_security
= (lp_security() == SEC_DOMAIN
);
1736 if (valid_workgroup
&& valid_security
) {
1737 /* nothing to be done */
1742 valid_realm
= strequal(lp_realm(), r
->out
.dns_domain_name
);
1743 switch (lp_security()) {
1746 valid_security
= true;
1749 if (valid_workgroup
&& valid_realm
&& valid_security
) {
1750 /* nothing to be done */
1756 /* check if we are supposed to manipulate configuration */
1758 if (!r
->in
.modify_config
) {
1760 char *wrong_conf
= talloc_strdup(mem_ctx
, "");
1762 if (!valid_workgroup
) {
1763 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1764 "\"workgroup\" set to '%s', should be '%s'",
1765 lp_workgroup(), r
->out
.netbios_domain_name
);
1766 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1770 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1771 "\"realm\" set to '%s', should be '%s'",
1772 lp_realm(), r
->out
.dns_domain_name
);
1773 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1776 if (!valid_security
) {
1777 const char *sec
= NULL
;
1778 switch (lp_security()) {
1779 case SEC_SHARE
: sec
= "share"; break;
1780 case SEC_USER
: sec
= "user"; break;
1781 case SEC_DOMAIN
: sec
= "domain"; break;
1782 case SEC_ADS
: sec
= "ads"; break;
1784 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1785 "\"security\" set to '%s', should be %s",
1786 sec
, r
->out
.domain_is_ad
?
1787 "either 'domain' or 'ads'" : "'domain'");
1788 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1791 libnet_join_set_error_string(mem_ctx
, r
,
1792 "Invalid configuration (%s) and configuration modification "
1793 "was not requested", wrong_conf
);
1794 return WERR_CAN_NOT_COMPLETE
;
1797 /* check if we are able to manipulate configuration */
1799 if (!lp_config_backend_is_registry()) {
1800 libnet_join_set_error_string(mem_ctx
, r
,
1801 "Configuration manipulation requested but not "
1802 "supported by backend");
1803 return WERR_NOT_SUPPORTED
;
1809 /****************************************************************
1810 ****************************************************************/
1812 static WERROR
libnet_DomainJoin(TALLOC_CTX
*mem_ctx
,
1813 struct libnet_JoinCtx
*r
)
1817 struct cli_state
*cli
= NULL
;
1819 ADS_STATUS ads_status
;
1820 #endif /* WITH_ADS */
1822 if (!r
->in
.dc_name
) {
1823 struct netr_DsRGetDCNameInfo
*info
;
1825 status
= dsgetdcname(mem_ctx
,
1830 DS_FORCE_REDISCOVERY
|
1831 DS_DIRECTORY_SERVICE_REQUIRED
|
1832 DS_WRITABLE_REQUIRED
|
1835 if (!NT_STATUS_IS_OK(status
)) {
1836 libnet_join_set_error_string(mem_ctx
, r
,
1837 "failed to find DC for domain %s",
1839 get_friendly_nt_error_msg(status
));
1840 return WERR_DCNOTFOUND
;
1843 dc
= strip_hostname(info
->dc_unc
);
1844 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
1845 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
1848 status
= libnet_join_lookup_dc_rpc(mem_ctx
, r
, &cli
);
1849 if (!NT_STATUS_IS_OK(status
)) {
1850 libnet_join_set_error_string(mem_ctx
, r
,
1851 "failed to lookup DC info for domain '%s' over rpc: %s",
1852 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
1853 return ntstatus_to_werror(status
);
1856 werr
= libnet_join_check_config(mem_ctx
, r
);
1857 if (!W_ERROR_IS_OK(werr
)) {
1862 if (r
->out
.domain_is_ad
&& r
->in
.account_ou
&&
1863 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1865 ads_status
= libnet_join_connect_ads(mem_ctx
, r
);
1866 if (!ADS_ERR_OK(ads_status
)) {
1867 return WERR_DEFAULT_JOIN_REQUIRED
;
1870 ads_status
= libnet_join_precreate_machine_acct(mem_ctx
, r
);
1871 if (!ADS_ERR_OK(ads_status
)) {
1872 libnet_join_set_error_string(mem_ctx
, r
,
1873 "failed to precreate account in ou %s: %s",
1875 ads_errstr(ads_status
));
1876 return WERR_DEFAULT_JOIN_REQUIRED
;
1879 r
->in
.join_flags
&= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
;
1881 #endif /* WITH_ADS */
1883 if ((r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
) &&
1884 (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED
)) {
1885 status
= libnet_join_joindomain_rpc_unsecure(mem_ctx
, r
, cli
);
1887 status
= libnet_join_joindomain_rpc(mem_ctx
, r
, cli
);
1889 if (!NT_STATUS_IS_OK(status
)) {
1890 libnet_join_set_error_string(mem_ctx
, r
,
1891 "failed to join domain '%s' over rpc: %s",
1892 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
1893 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
1894 return WERR_SETUP_ALREADY_JOINED
;
1896 werr
= ntstatus_to_werror(status
);
1900 if (!libnet_join_joindomain_store_secrets(mem_ctx
, r
)) {
1901 werr
= WERR_SETUP_NOT_JOINED
;
1915 /****************************************************************
1916 ****************************************************************/
1918 static WERROR
libnet_join_rollback(TALLOC_CTX
*mem_ctx
,
1919 struct libnet_JoinCtx
*r
)
1922 struct libnet_UnjoinCtx
*u
= NULL
;
1924 werr
= libnet_init_UnjoinCtx(mem_ctx
, &u
);
1925 if (!W_ERROR_IS_OK(werr
)) {
1929 u
->in
.debug
= r
->in
.debug
;
1930 u
->in
.dc_name
= r
->in
.dc_name
;
1931 u
->in
.domain_name
= r
->in
.domain_name
;
1932 u
->in
.admin_account
= r
->in
.admin_account
;
1933 u
->in
.admin_password
= r
->in
.admin_password
;
1934 u
->in
.modify_config
= r
->in
.modify_config
;
1935 u
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1936 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
1938 werr
= libnet_Unjoin(mem_ctx
, u
);
1944 /****************************************************************
1945 ****************************************************************/
1947 WERROR
libnet_Join(TALLOC_CTX
*mem_ctx
,
1948 struct libnet_JoinCtx
*r
)
1953 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx
, r
);
1956 werr
= libnet_join_pre_processing(mem_ctx
, r
);
1957 if (!W_ERROR_IS_OK(werr
)) {
1961 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1962 werr
= libnet_DomainJoin(mem_ctx
, r
);
1963 if (!W_ERROR_IS_OK(werr
)) {
1968 werr
= libnet_join_post_processing(mem_ctx
, r
);
1969 if (!W_ERROR_IS_OK(werr
)) {
1973 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1974 werr
= libnet_join_post_verify(mem_ctx
, r
);
1975 if (!W_ERROR_IS_OK(werr
)) {
1976 libnet_join_rollback(mem_ctx
, r
);
1981 r
->out
.result
= werr
;
1984 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx
, r
);
1989 /****************************************************************
1990 ****************************************************************/
1992 static WERROR
libnet_DomainUnjoin(TALLOC_CTX
*mem_ctx
,
1993 struct libnet_UnjoinCtx
*r
)
1997 if (!r
->in
.domain_sid
) {
1999 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid
)) {
2000 libnet_unjoin_set_error_string(mem_ctx
, r
,
2001 "Unable to fetch domain sid: are we joined?");
2002 return WERR_SETUP_NOT_JOINED
;
2004 r
->in
.domain_sid
= sid_dup_talloc(mem_ctx
, &sid
);
2005 W_ERROR_HAVE_NO_MEMORY(r
->in
.domain_sid
);
2008 if (!(r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) &&
2009 !r
->in
.delete_machine_account
) {
2010 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2014 if (!r
->in
.dc_name
) {
2015 struct netr_DsRGetDCNameInfo
*info
;
2017 status
= dsgetdcname(mem_ctx
,
2022 DS_DIRECTORY_SERVICE_REQUIRED
|
2023 DS_WRITABLE_REQUIRED
|
2026 if (!NT_STATUS_IS_OK(status
)) {
2027 libnet_unjoin_set_error_string(mem_ctx
, r
,
2028 "failed to find DC for domain %s",
2030 get_friendly_nt_error_msg(status
));
2031 return WERR_DCNOTFOUND
;
2034 dc
= strip_hostname(info
->dc_unc
);
2035 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
2036 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
2040 /* for net ads leave, try to delete the account. If it works,
2041 no sense in disabling. If it fails, we can still try to
2044 if (r
->in
.delete_machine_account
) {
2045 ADS_STATUS ads_status
;
2046 ads_status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
2047 if (ADS_ERR_OK(ads_status
)) {
2049 r
->out
.dns_domain_name
=
2050 talloc_strdup(mem_ctx
,
2051 r
->in
.ads
->server
.realm
);
2053 libnet_unjoin_remove_machine_acct(mem_ctx
, r
);
2055 if (!ADS_ERR_OK(ads_status
)) {
2056 libnet_unjoin_set_error_string(mem_ctx
, r
,
2057 "failed to remove machine account from AD: %s",
2058 ads_errstr(ads_status
));
2060 r
->out
.deleted_machine_account
= true;
2061 W_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
2062 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2066 #endif /* WITH_ADS */
2068 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2070 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) {
2071 status
= libnet_join_unjoindomain_rpc(mem_ctx
, r
);
2072 if (!NT_STATUS_IS_OK(status
)) {
2073 libnet_unjoin_set_error_string(mem_ctx
, r
,
2074 "failed to disable machine account via rpc: %s",
2075 get_friendly_nt_error_msg(status
));
2076 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
2077 return WERR_SETUP_NOT_JOINED
;
2079 return ntstatus_to_werror(status
);
2082 r
->out
.disabled_machine_account
= true;
2085 /* If disable succeeded or was not requested at all, we
2086 should be getting rid of our end of things */
2088 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2093 /****************************************************************
2094 ****************************************************************/
2096 static WERROR
libnet_unjoin_pre_processing(TALLOC_CTX
*mem_ctx
,
2097 struct libnet_UnjoinCtx
*r
)
2099 if (!r
->in
.domain_name
) {
2100 libnet_unjoin_set_error_string(mem_ctx
, r
,
2101 "No domain name defined");
2102 return WERR_INVALID_PARAM
;
2105 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
2108 libnet_unjoin_set_error_string(mem_ctx
, r
,
2109 "Failed to parse domain name");
2110 return WERR_INVALID_PARAM
;
2114 return WERR_SETUP_DOMAIN_CONTROLLER
;
2117 if (!secrets_init()) {
2118 libnet_unjoin_set_error_string(mem_ctx
, r
,
2119 "Unable to open secrets database");
2120 return WERR_CAN_NOT_COMPLETE
;
2126 /****************************************************************
2127 ****************************************************************/
2129 static WERROR
libnet_unjoin_post_processing(TALLOC_CTX
*mem_ctx
,
2130 struct libnet_UnjoinCtx
*r
)
2132 saf_delete(r
->out
.netbios_domain_name
);
2133 saf_delete(r
->out
.dns_domain_name
);
2135 return libnet_unjoin_config(r
);
2138 /****************************************************************
2139 ****************************************************************/
2141 WERROR
libnet_Unjoin(TALLOC_CTX
*mem_ctx
,
2142 struct libnet_UnjoinCtx
*r
)
2147 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx
, r
);
2150 werr
= libnet_unjoin_pre_processing(mem_ctx
, r
);
2151 if (!W_ERROR_IS_OK(werr
)) {
2155 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2156 werr
= libnet_DomainUnjoin(mem_ctx
, r
);
2157 if (!W_ERROR_IS_OK(werr
)) {
2158 libnet_unjoin_config(r
);
2163 werr
= libnet_unjoin_post_processing(mem_ctx
, r
);
2164 if (!W_ERROR_IS_OK(werr
)) {
2169 r
->out
.result
= werr
;
2172 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx
, r
);