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/ndr_samr_c.h"
27 #include "rpc_client/init_samr.h"
28 #include "../librpc/gen_ndr/ndr_lsa_c.h"
29 #include "rpc_client/cli_lsarpc.h"
30 #include "../librpc/gen_ndr/ndr_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 #include "../libcli/security/security.h"
40 /****************************************************************
41 ****************************************************************/
43 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
46 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
47 DEBUG(1,("libnet_Join:\n%s", str)); \
51 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
52 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
53 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
54 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
56 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
59 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
60 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
64 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
65 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
66 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
67 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
69 /****************************************************************
70 ****************************************************************/
72 static void libnet_join_set_error_string(TALLOC_CTX
*mem_ctx
,
73 struct libnet_JoinCtx
*r
,
74 const char *format
, ...)
78 if (r
->out
.error_string
) {
82 va_start(args
, format
);
83 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
87 /****************************************************************
88 ****************************************************************/
90 static void libnet_unjoin_set_error_string(TALLOC_CTX
*mem_ctx
,
91 struct libnet_UnjoinCtx
*r
,
92 const char *format
, ...)
96 if (r
->out
.error_string
) {
100 va_start(args
, format
);
101 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
107 /****************************************************************
108 ****************************************************************/
110 static ADS_STATUS
libnet_connect_ads(const char *dns_domain_name
,
111 const char *netbios_domain_name
,
113 const char *user_name
,
114 const char *password
,
118 ADS_STRUCT
*my_ads
= NULL
;
121 my_ads
= ads_init(dns_domain_name
,
125 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
129 SAFE_FREE(my_ads
->auth
.user_name
);
130 my_ads
->auth
.user_name
= SMB_STRDUP(user_name
);
131 if ((cp
= strchr_m(my_ads
->auth
.user_name
, '@'))!=0) {
133 SAFE_FREE(my_ads
->auth
.realm
);
134 my_ads
->auth
.realm
= smb_xstrdup(cp
);
135 strupper_m(my_ads
->auth
.realm
);
140 SAFE_FREE(my_ads
->auth
.password
);
141 my_ads
->auth
.password
= SMB_STRDUP(password
);
144 status
= ads_connect_user_creds(my_ads
);
145 if (!ADS_ERR_OK(status
)) {
146 ads_destroy(&my_ads
);
154 /****************************************************************
155 ****************************************************************/
157 static ADS_STATUS
libnet_join_connect_ads(TALLOC_CTX
*mem_ctx
,
158 struct libnet_JoinCtx
*r
)
162 status
= libnet_connect_ads(r
->out
.dns_domain_name
,
163 r
->out
.netbios_domain_name
,
166 r
->in
.admin_password
,
168 if (!ADS_ERR_OK(status
)) {
169 libnet_join_set_error_string(mem_ctx
, r
,
170 "failed to connect to AD: %s",
175 if (!r
->out
.netbios_domain_name
) {
176 r
->out
.netbios_domain_name
= talloc_strdup(mem_ctx
,
177 r
->in
.ads
->server
.workgroup
);
178 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.netbios_domain_name
);
181 if (!r
->out
.dns_domain_name
) {
182 r
->out
.dns_domain_name
= talloc_strdup(mem_ctx
,
183 r
->in
.ads
->config
.realm
);
184 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
187 r
->out
.domain_is_ad
= true;
192 /****************************************************************
193 ****************************************************************/
195 static ADS_STATUS
libnet_unjoin_connect_ads(TALLOC_CTX
*mem_ctx
,
196 struct libnet_UnjoinCtx
*r
)
200 status
= libnet_connect_ads(r
->in
.domain_name
,
204 r
->in
.admin_password
,
206 if (!ADS_ERR_OK(status
)) {
207 libnet_unjoin_set_error_string(mem_ctx
, r
,
208 "failed to connect to AD: %s",
215 /****************************************************************
216 join a domain using ADS (LDAP mods)
217 ****************************************************************/
219 static ADS_STATUS
libnet_join_precreate_machine_acct(TALLOC_CTX
*mem_ctx
,
220 struct libnet_JoinCtx
*r
)
223 LDAPMessage
*res
= NULL
;
224 const char *attrs
[] = { "dn", NULL
};
227 status
= ads_check_ou_dn(mem_ctx
, r
->in
.ads
, &r
->in
.account_ou
);
228 if (!ADS_ERR_OK(status
)) {
232 status
= ads_search_dn(r
->in
.ads
, &res
, r
->in
.account_ou
, attrs
);
233 if (!ADS_ERR_OK(status
)) {
237 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
238 ads_msgfree(r
->in
.ads
, res
);
239 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT
);
242 ads_msgfree(r
->in
.ads
, res
);
244 /* Attempt to create the machine account and bail if this fails.
245 Assume that the admin wants exactly what they requested */
247 status
= ads_create_machine_acct(r
->in
.ads
,
251 if (ADS_ERR_OK(status
)) {
252 DEBUG(1,("machine account creation created\n"));
254 } else if ((status
.error_type
== ENUM_ADS_ERROR_LDAP
) &&
255 (status
.err
.rc
== LDAP_ALREADY_EXISTS
)) {
256 status
= ADS_SUCCESS
;
259 if (!ADS_ERR_OK(status
)) {
260 DEBUG(1,("machine account creation failed\n"));
264 status
= ads_move_machine_acct(r
->in
.ads
,
268 if (!ADS_ERR_OK(status
)) {
269 DEBUG(1,("failure to locate/move pre-existing "
270 "machine account\n"));
274 DEBUG(1,("The machine account %s the specified OU.\n",
275 moved
? "was moved into" : "already exists in"));
280 /****************************************************************
281 ****************************************************************/
283 static ADS_STATUS
libnet_unjoin_remove_machine_acct(TALLOC_CTX
*mem_ctx
,
284 struct libnet_UnjoinCtx
*r
)
289 status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
290 if (!ADS_ERR_OK(status
)) {
291 libnet_unjoin_set_error_string(mem_ctx
, r
,
292 "failed to connect to AD: %s",
298 status
= ads_leave_realm(r
->in
.ads
, r
->in
.machine_name
);
299 if (!ADS_ERR_OK(status
)) {
300 libnet_unjoin_set_error_string(mem_ctx
, r
,
301 "failed to leave realm: %s",
309 /****************************************************************
310 ****************************************************************/
312 static ADS_STATUS
libnet_join_find_machine_acct(TALLOC_CTX
*mem_ctx
,
313 struct libnet_JoinCtx
*r
)
316 LDAPMessage
*res
= NULL
;
319 if (!r
->in
.machine_name
) {
320 return ADS_ERROR(LDAP_NO_MEMORY
);
323 status
= ads_find_machine_acct(r
->in
.ads
,
326 if (!ADS_ERR_OK(status
)) {
330 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
331 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
335 dn
= ads_get_dn(r
->in
.ads
, mem_ctx
, res
);
337 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
341 r
->out
.dn
= talloc_strdup(mem_ctx
, dn
);
343 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
348 ads_msgfree(r
->in
.ads
, res
);
354 /****************************************************************
355 Set a machines dNSHostName and servicePrincipalName attributes
356 ****************************************************************/
358 static ADS_STATUS
libnet_join_set_machine_spn(TALLOC_CTX
*mem_ctx
,
359 struct libnet_JoinCtx
*r
)
364 const char *spn_array
[3] = {NULL
, NULL
, NULL
};
369 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
370 if (!ADS_ERR_OK(status
)) {
374 /* Windows only creates HOST/shortname & HOST/fqdn. */
376 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", r
->in
.machine_name
);
378 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
383 if (!name_to_fqdn(my_fqdn
, r
->in
.machine_name
)
384 || (strchr(my_fqdn
, '.') == NULL
)) {
385 fstr_sprintf(my_fqdn
, "%s.%s", r
->in
.machine_name
,
386 r
->out
.dns_domain_name
);
391 if (!strequal(my_fqdn
, r
->in
.machine_name
)) {
392 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", my_fqdn
);
394 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
399 mods
= ads_init_mods(mem_ctx
);
401 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
404 /* fields of primary importance */
406 status
= ads_mod_str(mem_ctx
, &mods
, "dNSHostName", my_fqdn
);
407 if (!ADS_ERR_OK(status
)) {
408 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
411 status
= ads_mod_strlist(mem_ctx
, &mods
, "servicePrincipalName",
413 if (!ADS_ERR_OK(status
)) {
414 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
417 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
420 /****************************************************************
421 ****************************************************************/
423 static ADS_STATUS
libnet_join_set_machine_upn(TALLOC_CTX
*mem_ctx
,
424 struct libnet_JoinCtx
*r
)
429 if (!r
->in
.create_upn
) {
435 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
436 if (!ADS_ERR_OK(status
)) {
441 r
->in
.upn
= talloc_asprintf(mem_ctx
,
444 r
->out
.dns_domain_name
);
446 return ADS_ERROR(LDAP_NO_MEMORY
);
450 /* now do the mods */
452 mods
= ads_init_mods(mem_ctx
);
454 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
457 /* fields of primary importance */
459 status
= ads_mod_str(mem_ctx
, &mods
, "userPrincipalName", r
->in
.upn
);
460 if (!ADS_ERR_OK(status
)) {
461 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
464 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
468 /****************************************************************
469 ****************************************************************/
471 static ADS_STATUS
libnet_join_set_os_attributes(TALLOC_CTX
*mem_ctx
,
472 struct libnet_JoinCtx
*r
)
478 if (!r
->in
.os_name
|| !r
->in
.os_version
) {
484 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
485 if (!ADS_ERR_OK(status
)) {
489 /* now do the mods */
491 mods
= ads_init_mods(mem_ctx
);
493 return ADS_ERROR(LDAP_NO_MEMORY
);
496 os_sp
= talloc_asprintf(mem_ctx
, "Samba %s", samba_version_string());
498 return ADS_ERROR(LDAP_NO_MEMORY
);
501 /* fields of primary importance */
503 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystem",
505 if (!ADS_ERR_OK(status
)) {
509 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemVersion",
511 if (!ADS_ERR_OK(status
)) {
515 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemServicePack",
517 if (!ADS_ERR_OK(status
)) {
521 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
524 /****************************************************************
525 ****************************************************************/
527 static bool libnet_join_create_keytab(TALLOC_CTX
*mem_ctx
,
528 struct libnet_JoinCtx
*r
)
530 if (!USE_SYSTEM_KEYTAB
) {
534 if (ads_keytab_create_default(r
->in
.ads
) != 0) {
541 /****************************************************************
542 ****************************************************************/
544 static bool libnet_join_derive_salting_principal(TALLOC_CTX
*mem_ctx
,
545 struct libnet_JoinCtx
*r
)
547 uint32_t domain_func
;
549 const char *salt
= NULL
;
550 char *std_salt
= NULL
;
552 status
= ads_domain_func_level(r
->in
.ads
, &domain_func
);
553 if (!ADS_ERR_OK(status
)) {
554 libnet_join_set_error_string(mem_ctx
, r
,
555 "failed to determine domain functional level: %s",
560 /* go ahead and setup the default salt */
562 std_salt
= kerberos_standard_des_salt();
564 libnet_join_set_error_string(mem_ctx
, r
,
565 "failed to obtain standard DES salt");
569 salt
= talloc_strdup(mem_ctx
, std_salt
);
576 /* if it's a Windows functional domain, we have to look for the UPN */
578 if (domain_func
== DS_DOMAIN_FUNCTION_2000
) {
581 upn
= ads_get_upn(r
->in
.ads
, mem_ctx
,
584 salt
= talloc_strdup(mem_ctx
, upn
);
591 return kerberos_secrets_store_des_salt(salt
);
594 /****************************************************************
595 ****************************************************************/
597 static ADS_STATUS
libnet_join_post_processing_ads(TALLOC_CTX
*mem_ctx
,
598 struct libnet_JoinCtx
*r
)
603 status
= libnet_join_connect_ads(mem_ctx
, r
);
604 if (!ADS_ERR_OK(status
)) {
609 status
= libnet_join_set_machine_spn(mem_ctx
, r
);
610 if (!ADS_ERR_OK(status
)) {
611 libnet_join_set_error_string(mem_ctx
, r
,
612 "failed to set machine spn: %s",
617 status
= libnet_join_set_os_attributes(mem_ctx
, r
);
618 if (!ADS_ERR_OK(status
)) {
619 libnet_join_set_error_string(mem_ctx
, r
,
620 "failed to set machine os attributes: %s",
625 status
= libnet_join_set_machine_upn(mem_ctx
, r
);
626 if (!ADS_ERR_OK(status
)) {
627 libnet_join_set_error_string(mem_ctx
, r
,
628 "failed to set machine upn: %s",
633 if (!libnet_join_derive_salting_principal(mem_ctx
, r
)) {
634 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
637 if (!libnet_join_create_keytab(mem_ctx
, r
)) {
638 libnet_join_set_error_string(mem_ctx
, r
,
639 "failed to create kerberos keytab");
640 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
645 #endif /* WITH_ADS */
647 /****************************************************************
648 Store the machine password and domain SID
649 ****************************************************************/
651 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX
*mem_ctx
,
652 struct libnet_JoinCtx
*r
)
654 if (!secrets_store_domain_sid(r
->out
.netbios_domain_name
,
657 DEBUG(1,("Failed to save domain sid\n"));
661 if (!secrets_store_machine_password(r
->in
.machine_password
,
662 r
->out
.netbios_domain_name
,
663 r
->in
.secure_channel_type
))
665 DEBUG(1,("Failed to save machine password\n"));
672 /****************************************************************
673 Connect dc's IPC$ share
674 ****************************************************************/
676 static NTSTATUS
libnet_join_connect_dc_ipc(const char *dc
,
680 struct cli_state
**cli
)
685 flags
|= CLI_FULL_CONNECTION_USE_KERBEROS
;
688 if (use_kerberos
&& pass
) {
689 flags
|= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS
;
692 return cli_full_connection(cli
, NULL
,
703 /****************************************************************
704 Lookup domain dc's info
705 ****************************************************************/
707 static NTSTATUS
libnet_join_lookup_dc_rpc(TALLOC_CTX
*mem_ctx
,
708 struct libnet_JoinCtx
*r
,
709 struct cli_state
**cli
)
711 struct rpc_pipe_client
*pipe_hnd
= NULL
;
712 struct policy_handle lsa_pol
;
713 NTSTATUS status
, result
;
714 union lsa_PolicyInformation
*info
= NULL
;
715 struct dcerpc_binding_handle
*b
;
717 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
719 r
->in
.admin_password
,
722 if (!NT_STATUS_IS_OK(status
)) {
726 status
= cli_rpc_pipe_open_noauth(*cli
, &ndr_table_lsarpc
.syntax_id
,
728 if (!NT_STATUS_IS_OK(status
)) {
729 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
734 b
= pipe_hnd
->binding_handle
;
736 status
= rpccli_lsa_open_policy(pipe_hnd
, mem_ctx
, true,
737 SEC_FLAG_MAXIMUM_ALLOWED
, &lsa_pol
);
738 if (!NT_STATUS_IS_OK(status
)) {
742 status
= dcerpc_lsa_QueryInfoPolicy2(b
, mem_ctx
,
747 if (NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(result
)) {
748 r
->out
.domain_is_ad
= true;
749 r
->out
.netbios_domain_name
= info
->dns
.name
.string
;
750 r
->out
.dns_domain_name
= info
->dns
.dns_domain
.string
;
751 r
->out
.forest_name
= info
->dns
.dns_forest
.string
;
752 r
->out
.domain_sid
= dom_sid_dup(mem_ctx
, info
->dns
.sid
);
753 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
756 if (!NT_STATUS_IS_OK(status
)) {
757 status
= dcerpc_lsa_QueryInfoPolicy(b
, mem_ctx
,
759 LSA_POLICY_INFO_ACCOUNT_DOMAIN
,
762 if (!NT_STATUS_IS_OK(status
)) {
765 if (!NT_STATUS_IS_OK(result
)) {
770 r
->out
.netbios_domain_name
= info
->account_domain
.name
.string
;
771 r
->out
.domain_sid
= dom_sid_dup(mem_ctx
, info
->account_domain
.sid
);
772 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
775 dcerpc_lsa_Close(b
, mem_ctx
, &lsa_pol
, &result
);
776 TALLOC_FREE(pipe_hnd
);
782 /****************************************************************
783 Do the domain join unsecure
784 ****************************************************************/
786 static NTSTATUS
libnet_join_joindomain_rpc_unsecure(TALLOC_CTX
*mem_ctx
,
787 struct libnet_JoinCtx
*r
,
788 struct cli_state
*cli
)
790 struct rpc_pipe_client
*pipe_hnd
= NULL
;
791 unsigned char orig_trust_passwd_hash
[16];
792 unsigned char new_trust_passwd_hash
[16];
793 fstring trust_passwd
;
796 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_netlogon
.syntax_id
,
798 if (!NT_STATUS_IS_OK(status
)) {
802 if (!r
->in
.machine_password
) {
803 r
->in
.machine_password
= generate_random_str(mem_ctx
, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
804 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
807 E_md4hash(r
->in
.machine_password
, new_trust_passwd_hash
);
809 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
810 fstrcpy(trust_passwd
, r
->in
.admin_password
);
811 strlower_m(trust_passwd
);
814 * Machine names can be 15 characters, but the max length on
815 * a password is 14. --jerry
818 trust_passwd
[14] = '\0';
820 E_md4hash(trust_passwd
, orig_trust_passwd_hash
);
822 status
= rpccli_netlogon_set_trust_password(pipe_hnd
, mem_ctx
,
824 orig_trust_passwd_hash
,
825 r
->in
.machine_password
,
826 new_trust_passwd_hash
,
827 r
->in
.secure_channel_type
);
832 /****************************************************************
834 ****************************************************************/
836 static NTSTATUS
libnet_join_joindomain_rpc(TALLOC_CTX
*mem_ctx
,
837 struct libnet_JoinCtx
*r
,
838 struct cli_state
*cli
)
840 struct rpc_pipe_client
*pipe_hnd
= NULL
;
841 struct policy_handle sam_pol
, domain_pol
, user_pol
;
842 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
, result
;
844 struct lsa_String lsa_acct_name
;
846 uint32_t acct_flags
= ACB_WSTRUST
;
847 struct samr_Ids user_rids
;
848 struct samr_Ids name_types
;
849 union samr_UserInfo user_info
;
850 struct dcerpc_binding_handle
*b
= NULL
;
852 struct samr_CryptPassword crypt_pwd
;
853 struct samr_CryptPasswordEx crypt_pwd_ex
;
855 ZERO_STRUCT(sam_pol
);
856 ZERO_STRUCT(domain_pol
);
857 ZERO_STRUCT(user_pol
);
859 switch (r
->in
.secure_channel_type
) {
861 acct_flags
= ACB_WSTRUST
;
864 acct_flags
= ACB_SVRTRUST
;
867 return NT_STATUS_INVALID_PARAMETER
;
870 if (!r
->in
.machine_password
) {
871 r
->in
.machine_password
= generate_random_str(mem_ctx
, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
872 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
875 /* Open the domain */
877 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
879 if (!NT_STATUS_IS_OK(status
)) {
880 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
885 b
= pipe_hnd
->binding_handle
;
887 status
= dcerpc_samr_Connect2(b
, mem_ctx
,
889 SAMR_ACCESS_ENUM_DOMAINS
890 | SAMR_ACCESS_LOOKUP_DOMAIN
,
893 if (!NT_STATUS_IS_OK(status
)) {
896 if (!NT_STATUS_IS_OK(result
)) {
901 status
= dcerpc_samr_OpenDomain(b
, mem_ctx
,
903 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
904 | SAMR_DOMAIN_ACCESS_CREATE_USER
905 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT
,
909 if (!NT_STATUS_IS_OK(status
)) {
912 if (!NT_STATUS_IS_OK(result
)) {
917 /* Create domain user */
919 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
920 strlower_m(acct_name
);
922 init_lsa_String(&lsa_acct_name
, acct_name
);
924 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
) {
925 uint32_t access_desired
=
926 SEC_GENERIC_READ
| SEC_GENERIC_WRITE
| SEC_GENERIC_EXECUTE
|
927 SEC_STD_WRITE_DAC
| SEC_STD_DELETE
|
928 SAMR_USER_ACCESS_SET_PASSWORD
|
929 SAMR_USER_ACCESS_GET_ATTRIBUTES
|
930 SAMR_USER_ACCESS_SET_ATTRIBUTES
;
931 uint32_t access_granted
= 0;
933 DEBUG(10,("Creating account with desired access mask: %d\n",
936 status
= dcerpc_samr_CreateUser2(b
, mem_ctx
,
945 if (!NT_STATUS_IS_OK(status
)) {
950 if (!NT_STATUS_IS_OK(status
) &&
951 !NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
953 DEBUG(10,("Creation of workstation account failed: %s\n",
956 /* If NT_STATUS_ACCESS_DENIED then we have a valid
957 username/password combo but the user does not have
958 administrator access. */
960 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
961 libnet_join_set_error_string(mem_ctx
, r
,
962 "User specified does not have "
963 "administrator privileges");
969 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
970 if (!(r
->in
.join_flags
&
971 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
)) {
976 /* We *must* do this.... don't ask... */
978 if (NT_STATUS_IS_OK(status
)) {
979 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
983 status
= dcerpc_samr_LookupNames(b
, mem_ctx
,
990 if (!NT_STATUS_IS_OK(status
)) {
993 if (!NT_STATUS_IS_OK(result
)) {
998 if (name_types
.ids
[0] != SID_NAME_USER
) {
999 DEBUG(0,("%s is not a user account (type=%d)\n",
1000 acct_name
, name_types
.ids
[0]));
1001 status
= NT_STATUS_INVALID_WORKSTATION
;
1005 user_rid
= user_rids
.ids
[0];
1007 /* Open handle on user */
1009 status
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1011 SEC_FLAG_MAXIMUM_ALLOWED
,
1015 if (!NT_STATUS_IS_OK(status
)) {
1018 if (!NT_STATUS_IS_OK(result
)) {
1023 /* Fill in the additional account flags now */
1025 acct_flags
|= ACB_PWNOEXP
;
1027 /* Set account flags on machine account */
1028 ZERO_STRUCT(user_info
.info16
);
1029 user_info
.info16
.acct_flags
= acct_flags
;
1031 status
= dcerpc_samr_SetUserInfo(b
, mem_ctx
,
1036 if (!NT_STATUS_IS_OK(status
)) {
1037 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1041 libnet_join_set_error_string(mem_ctx
, r
,
1042 "Failed to set account flags for machine account (%s)\n",
1047 if (!NT_STATUS_IS_OK(result
)) {
1050 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1054 libnet_join_set_error_string(mem_ctx
, r
,
1055 "Failed to set account flags for machine account (%s)\n",
1060 /* Set password on machine account - first try level 26 */
1062 init_samr_CryptPasswordEx(r
->in
.machine_password
,
1063 &cli
->user_session_key
,
1066 user_info
.info26
.password
= crypt_pwd_ex
;
1067 user_info
.info26
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1069 status
= dcerpc_samr_SetUserInfo2(b
, mem_ctx
,
1075 if (NT_STATUS_EQUAL(status
, NT_STATUS(DCERPC_FAULT_INVALID_TAG
))) {
1077 /* retry with level 24 */
1079 init_samr_CryptPassword(r
->in
.machine_password
,
1080 &cli
->user_session_key
,
1083 user_info
.info24
.password
= crypt_pwd
;
1084 user_info
.info24
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1086 status
= dcerpc_samr_SetUserInfo2(b
, mem_ctx
,
1093 if (!NT_STATUS_IS_OK(status
)) {
1095 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1099 libnet_join_set_error_string(mem_ctx
, r
,
1100 "Failed to set password for machine account (%s)\n",
1104 if (!NT_STATUS_IS_OK(result
)) {
1107 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1111 libnet_join_set_error_string(mem_ctx
, r
,
1112 "Failed to set password for machine account (%s)\n",
1117 status
= NT_STATUS_OK
;
1124 if (is_valid_policy_hnd(&sam_pol
)) {
1125 dcerpc_samr_Close(b
, mem_ctx
, &sam_pol
, &result
);
1127 if (is_valid_policy_hnd(&domain_pol
)) {
1128 dcerpc_samr_Close(b
, mem_ctx
, &domain_pol
, &result
);
1130 if (is_valid_policy_hnd(&user_pol
)) {
1131 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1133 TALLOC_FREE(pipe_hnd
);
1138 /****************************************************************
1139 ****************************************************************/
1141 NTSTATUS
libnet_join_ok(const char *netbios_domain_name
,
1142 const char *machine_name
,
1143 const char *dc_name
)
1145 uint32_t neg_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
1146 struct cli_state
*cli
= NULL
;
1147 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1148 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1150 char *machine_password
= NULL
;
1151 char *machine_account
= NULL
;
1154 return NT_STATUS_INVALID_PARAMETER
;
1157 if (!secrets_init()) {
1158 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1161 machine_password
= secrets_fetch_machine_password(netbios_domain_name
,
1163 if (!machine_password
) {
1164 return NT_STATUS_NO_TRUST_LSA_SECRET
;
1167 if (asprintf(&machine_account
, "%s$", machine_name
) == -1) {
1168 SAFE_FREE(machine_password
);
1169 return NT_STATUS_NO_MEMORY
;
1172 status
= cli_full_connection(&cli
, NULL
,
1181 free(machine_account
);
1182 free(machine_password
);
1184 if (!NT_STATUS_IS_OK(status
)) {
1185 status
= cli_full_connection(&cli
, NULL
,
1196 if (!NT_STATUS_IS_OK(status
)) {
1200 status
= get_schannel_session_key(cli
, netbios_domain_name
,
1201 &neg_flags
, &netlogon_pipe
);
1202 if (!NT_STATUS_IS_OK(status
)) {
1203 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_NETWORK_RESPONSE
)) {
1205 return NT_STATUS_OK
;
1208 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1209 "key from server %s for domain %s. Error was %s\n",
1210 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1215 if (!lp_client_schannel()) {
1217 return NT_STATUS_OK
;
1220 status
= cli_rpc_pipe_open_schannel_with_key(
1221 cli
, &ndr_table_netlogon
.syntax_id
, NCACN_NP
,
1222 DCERPC_AUTH_LEVEL_PRIVACY
,
1223 netbios_domain_name
, &netlogon_pipe
->dc
, &pipe_hnd
);
1227 if (!NT_STATUS_IS_OK(status
)) {
1228 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1229 "on netlogon pipe to server %s for domain %s. "
1231 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1235 return NT_STATUS_OK
;
1238 /****************************************************************
1239 ****************************************************************/
1241 static WERROR
libnet_join_post_verify(TALLOC_CTX
*mem_ctx
,
1242 struct libnet_JoinCtx
*r
)
1246 status
= libnet_join_ok(r
->out
.netbios_domain_name
,
1249 if (!NT_STATUS_IS_OK(status
)) {
1250 libnet_join_set_error_string(mem_ctx
, r
,
1251 "failed to verify domain membership after joining: %s",
1252 get_friendly_nt_error_msg(status
));
1253 return WERR_SETUP_NOT_JOINED
;
1259 /****************************************************************
1260 ****************************************************************/
1262 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX
*mem_ctx
,
1263 struct libnet_UnjoinCtx
*r
)
1265 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1269 if (!secrets_delete_domain_sid(lp_workgroup())) {
1276 /****************************************************************
1277 ****************************************************************/
1279 static NTSTATUS
libnet_join_unjoindomain_rpc(TALLOC_CTX
*mem_ctx
,
1280 struct libnet_UnjoinCtx
*r
)
1282 struct cli_state
*cli
= NULL
;
1283 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1284 struct policy_handle sam_pol
, domain_pol
, user_pol
;
1285 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
, result
;
1288 struct lsa_String lsa_acct_name
;
1289 struct samr_Ids user_rids
;
1290 struct samr_Ids name_types
;
1291 union samr_UserInfo
*info
= NULL
;
1292 struct dcerpc_binding_handle
*b
;
1294 ZERO_STRUCT(sam_pol
);
1295 ZERO_STRUCT(domain_pol
);
1296 ZERO_STRUCT(user_pol
);
1298 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
1299 r
->in
.admin_account
,
1300 r
->in
.admin_password
,
1303 if (!NT_STATUS_IS_OK(status
)) {
1307 /* Open the domain */
1309 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
1311 if (!NT_STATUS_IS_OK(status
)) {
1312 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1313 nt_errstr(status
)));
1317 b
= pipe_hnd
->binding_handle
;
1319 status
= dcerpc_samr_Connect2(b
, mem_ctx
,
1321 SEC_FLAG_MAXIMUM_ALLOWED
,
1324 if (!NT_STATUS_IS_OK(status
)) {
1327 if (!NT_STATUS_IS_OK(result
)) {
1332 status
= dcerpc_samr_OpenDomain(b
, mem_ctx
,
1334 SEC_FLAG_MAXIMUM_ALLOWED
,
1338 if (!NT_STATUS_IS_OK(status
)) {
1341 if (!NT_STATUS_IS_OK(result
)) {
1346 /* Create domain user */
1348 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
1349 strlower_m(acct_name
);
1351 init_lsa_String(&lsa_acct_name
, acct_name
);
1353 status
= dcerpc_samr_LookupNames(b
, mem_ctx
,
1361 if (!NT_STATUS_IS_OK(status
)) {
1364 if (!NT_STATUS_IS_OK(result
)) {
1369 if (name_types
.ids
[0] != SID_NAME_USER
) {
1370 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name
,
1371 name_types
.ids
[0]));
1372 status
= NT_STATUS_INVALID_WORKSTATION
;
1376 user_rid
= user_rids
.ids
[0];
1378 /* Open handle on user */
1380 status
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1382 SEC_FLAG_MAXIMUM_ALLOWED
,
1386 if (!NT_STATUS_IS_OK(status
)) {
1389 if (!NT_STATUS_IS_OK(result
)) {
1396 status
= dcerpc_samr_QueryUserInfo(b
, mem_ctx
,
1401 if (!NT_STATUS_IS_OK(status
)) {
1402 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1405 if (!NT_STATUS_IS_OK(result
)) {
1407 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1411 /* now disable and setuser info */
1413 info
->info16
.acct_flags
|= ACB_DISABLED
;
1415 status
= dcerpc_samr_SetUserInfo(b
, mem_ctx
,
1420 if (!NT_STATUS_IS_OK(status
)) {
1421 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1424 if (!NT_STATUS_IS_OK(result
)) {
1426 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1430 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1434 if (is_valid_policy_hnd(&domain_pol
)) {
1435 dcerpc_samr_Close(b
, mem_ctx
, &domain_pol
, &result
);
1437 if (is_valid_policy_hnd(&sam_pol
)) {
1438 dcerpc_samr_Close(b
, mem_ctx
, &sam_pol
, &result
);
1440 TALLOC_FREE(pipe_hnd
);
1450 /****************************************************************
1451 ****************************************************************/
1453 static WERROR
do_join_modify_vals_config(struct libnet_JoinCtx
*r
)
1456 struct smbconf_ctx
*ctx
;
1458 werr
= smbconf_init_reg(r
, &ctx
, NULL
);
1459 if (!W_ERROR_IS_OK(werr
)) {
1463 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1465 werr
= smbconf_set_global_parameter(ctx
, "security", "user");
1466 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1468 werr
= smbconf_set_global_parameter(ctx
, "workgroup",
1471 smbconf_delete_global_parameter(ctx
, "realm");
1475 werr
= smbconf_set_global_parameter(ctx
, "security", "domain");
1476 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1478 werr
= smbconf_set_global_parameter(ctx
, "workgroup",
1479 r
->out
.netbios_domain_name
);
1480 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1482 if (r
->out
.domain_is_ad
) {
1483 werr
= smbconf_set_global_parameter(ctx
, "security", "ads");
1484 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1486 werr
= smbconf_set_global_parameter(ctx
, "realm",
1487 r
->out
.dns_domain_name
);
1488 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1492 smbconf_shutdown(ctx
);
1496 /****************************************************************
1497 ****************************************************************/
1499 static WERROR
do_unjoin_modify_vals_config(struct libnet_UnjoinCtx
*r
)
1501 WERROR werr
= WERR_OK
;
1502 struct smbconf_ctx
*ctx
;
1504 werr
= smbconf_init_reg(r
, &ctx
, NULL
);
1505 if (!W_ERROR_IS_OK(werr
)) {
1509 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1511 werr
= smbconf_set_global_parameter(ctx
, "security", "user");
1512 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1514 werr
= smbconf_delete_global_parameter(ctx
, "workgroup");
1515 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1517 smbconf_delete_global_parameter(ctx
, "realm");
1521 smbconf_shutdown(ctx
);
1525 /****************************************************************
1526 ****************************************************************/
1528 static WERROR
do_JoinConfig(struct libnet_JoinCtx
*r
)
1532 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1533 return r
->out
.result
;
1536 if (!r
->in
.modify_config
) {
1540 werr
= do_join_modify_vals_config(r
);
1541 if (!W_ERROR_IS_OK(werr
)) {
1545 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1547 r
->out
.modified_config
= true;
1548 r
->out
.result
= werr
;
1553 /****************************************************************
1554 ****************************************************************/
1556 static WERROR
libnet_unjoin_config(struct libnet_UnjoinCtx
*r
)
1560 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1561 return r
->out
.result
;
1564 if (!r
->in
.modify_config
) {
1568 werr
= do_unjoin_modify_vals_config(r
);
1569 if (!W_ERROR_IS_OK(werr
)) {
1573 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1575 r
->out
.modified_config
= true;
1576 r
->out
.result
= werr
;
1581 /****************************************************************
1582 ****************************************************************/
1584 static bool libnet_parse_domain_dc(TALLOC_CTX
*mem_ctx
,
1585 const char *domain_str
,
1586 const char **domain_p
,
1589 char *domain
= NULL
;
1591 const char *p
= NULL
;
1593 if (!domain_str
|| !domain_p
|| !dc_p
) {
1597 p
= strchr_m(domain_str
, '\\');
1600 domain
= talloc_strndup(mem_ctx
, domain_str
,
1601 PTR_DIFF(p
, domain_str
));
1602 dc
= talloc_strdup(mem_ctx
, p
+1);
1607 domain
= talloc_strdup(mem_ctx
, domain_str
);
1623 /****************************************************************
1624 ****************************************************************/
1626 static WERROR
libnet_join_pre_processing(TALLOC_CTX
*mem_ctx
,
1627 struct libnet_JoinCtx
*r
)
1629 if (!r
->in
.domain_name
) {
1630 libnet_join_set_error_string(mem_ctx
, r
,
1631 "No domain name defined");
1632 return WERR_INVALID_PARAM
;
1635 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
1638 libnet_join_set_error_string(mem_ctx
, r
,
1639 "Failed to parse domain name");
1640 return WERR_INVALID_PARAM
;
1644 return WERR_SETUP_DOMAIN_CONTROLLER
;
1647 if (!secrets_init()) {
1648 libnet_join_set_error_string(mem_ctx
, r
,
1649 "Unable to open secrets database");
1650 return WERR_CAN_NOT_COMPLETE
;
1656 /****************************************************************
1657 ****************************************************************/
1659 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid
*domain_sid
)
1663 /* Try adding dom admins to builtin\admins. Only log failures. */
1664 status
= create_builtin_administrators(domain_sid
);
1665 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1666 DEBUG(10,("Unable to auto-add domain administrators to "
1667 "BUILTIN\\Administrators during join because "
1668 "winbindd must be running."));
1669 } else if (!NT_STATUS_IS_OK(status
)) {
1670 DEBUG(5, ("Failed to auto-add domain administrators to "
1671 "BUILTIN\\Administrators during join: %s\n",
1672 nt_errstr(status
)));
1675 /* Try adding dom users to builtin\users. Only log failures. */
1676 status
= create_builtin_users(domain_sid
);
1677 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1678 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1679 "during join because winbindd must be running."));
1680 } else if (!NT_STATUS_IS_OK(status
)) {
1681 DEBUG(5, ("Failed to auto-add domain administrators to "
1682 "BUILTIN\\Administrators during join: %s\n",
1683 nt_errstr(status
)));
1687 /****************************************************************
1688 ****************************************************************/
1690 static WERROR
libnet_join_post_processing(TALLOC_CTX
*mem_ctx
,
1691 struct libnet_JoinCtx
*r
)
1695 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1696 return r
->out
.result
;
1699 werr
= do_JoinConfig(r
);
1700 if (!W_ERROR_IS_OK(werr
)) {
1704 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1708 saf_join_store(r
->out
.netbios_domain_name
, r
->in
.dc_name
);
1709 if (r
->out
.dns_domain_name
) {
1710 saf_join_store(r
->out
.dns_domain_name
, r
->in
.dc_name
);
1714 if (r
->out
.domain_is_ad
&&
1715 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1716 ADS_STATUS ads_status
;
1718 ads_status
= libnet_join_post_processing_ads(mem_ctx
, r
);
1719 if (!ADS_ERR_OK(ads_status
)) {
1720 return WERR_GENERAL_FAILURE
;
1723 #endif /* WITH_ADS */
1725 libnet_join_add_dom_rids_to_builtins(r
->out
.domain_sid
);
1730 /****************************************************************
1731 ****************************************************************/
1733 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx
*r
)
1735 const char *krb5_cc_env
= NULL
;
1738 ads_destroy(&r
->in
.ads
);
1741 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1742 if (krb5_cc_env
&& StrCaseCmp(krb5_cc_env
, "MEMORY:libnetjoin")) {
1743 unsetenv(KRB5_ENV_CCNAME
);
1749 /****************************************************************
1750 ****************************************************************/
1752 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx
*r
)
1754 const char *krb5_cc_env
= NULL
;
1757 ads_destroy(&r
->in
.ads
);
1760 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1761 if (krb5_cc_env
&& StrCaseCmp(krb5_cc_env
, "MEMORY:libnetjoin")) {
1762 unsetenv(KRB5_ENV_CCNAME
);
1768 /****************************************************************
1769 ****************************************************************/
1771 WERROR
libnet_init_JoinCtx(TALLOC_CTX
*mem_ctx
,
1772 struct libnet_JoinCtx
**r
)
1774 struct libnet_JoinCtx
*ctx
;
1775 const char *krb5_cc_env
= NULL
;
1777 ctx
= talloc_zero(mem_ctx
, struct libnet_JoinCtx
);
1782 talloc_set_destructor(ctx
, libnet_destroy_JoinCtx
);
1784 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1785 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1787 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1788 if (!krb5_cc_env
|| (strlen(krb5_cc_env
) == 0)) {
1789 krb5_cc_env
= talloc_strdup(mem_ctx
, "MEMORY:libnetjoin");
1790 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env
);
1791 setenv(KRB5_ENV_CCNAME
, krb5_cc_env
, 1);
1794 ctx
->in
.secure_channel_type
= SEC_CHAN_WKSTA
;
1801 /****************************************************************
1802 ****************************************************************/
1804 WERROR
libnet_init_UnjoinCtx(TALLOC_CTX
*mem_ctx
,
1805 struct libnet_UnjoinCtx
**r
)
1807 struct libnet_UnjoinCtx
*ctx
;
1808 const char *krb5_cc_env
= NULL
;
1810 ctx
= talloc_zero(mem_ctx
, struct libnet_UnjoinCtx
);
1815 talloc_set_destructor(ctx
, libnet_destroy_UnjoinCtx
);
1817 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1818 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1820 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1821 if (!krb5_cc_env
|| (strlen(krb5_cc_env
) == 0)) {
1822 krb5_cc_env
= talloc_strdup(mem_ctx
, "MEMORY:libnetjoin");
1823 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env
);
1824 setenv(KRB5_ENV_CCNAME
, krb5_cc_env
, 1);
1832 /****************************************************************
1833 ****************************************************************/
1835 static WERROR
libnet_join_check_config(TALLOC_CTX
*mem_ctx
,
1836 struct libnet_JoinCtx
*r
)
1838 bool valid_security
= false;
1839 bool valid_workgroup
= false;
1840 bool valid_realm
= false;
1842 /* check if configuration is already set correctly */
1844 valid_workgroup
= strequal(lp_workgroup(), r
->out
.netbios_domain_name
);
1846 switch (r
->out
.domain_is_ad
) {
1848 valid_security
= (lp_security() == SEC_DOMAIN
);
1849 if (valid_workgroup
&& valid_security
) {
1850 /* nothing to be done */
1855 valid_realm
= strequal(lp_realm(), r
->out
.dns_domain_name
);
1856 switch (lp_security()) {
1859 valid_security
= true;
1862 if (valid_workgroup
&& valid_realm
&& valid_security
) {
1863 /* nothing to be done */
1869 /* check if we are supposed to manipulate configuration */
1871 if (!r
->in
.modify_config
) {
1873 char *wrong_conf
= talloc_strdup(mem_ctx
, "");
1875 if (!valid_workgroup
) {
1876 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1877 "\"workgroup\" set to '%s', should be '%s'",
1878 lp_workgroup(), r
->out
.netbios_domain_name
);
1879 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1883 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1884 "\"realm\" set to '%s', should be '%s'",
1885 lp_realm(), r
->out
.dns_domain_name
);
1886 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1889 if (!valid_security
) {
1890 const char *sec
= NULL
;
1891 switch (lp_security()) {
1892 case SEC_SHARE
: sec
= "share"; break;
1893 case SEC_USER
: sec
= "user"; break;
1894 case SEC_DOMAIN
: sec
= "domain"; break;
1895 case SEC_ADS
: sec
= "ads"; break;
1897 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1898 "\"security\" set to '%s', should be %s",
1899 sec
, r
->out
.domain_is_ad
?
1900 "either 'domain' or 'ads'" : "'domain'");
1901 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1904 libnet_join_set_error_string(mem_ctx
, r
,
1905 "Invalid configuration (%s) and configuration modification "
1906 "was not requested", wrong_conf
);
1907 return WERR_CAN_NOT_COMPLETE
;
1910 /* check if we are able to manipulate configuration */
1912 if (!lp_config_backend_is_registry()) {
1913 libnet_join_set_error_string(mem_ctx
, r
,
1914 "Configuration manipulation requested but not "
1915 "supported by backend");
1916 return WERR_NOT_SUPPORTED
;
1922 /****************************************************************
1923 ****************************************************************/
1925 static WERROR
libnet_DomainJoin(TALLOC_CTX
*mem_ctx
,
1926 struct libnet_JoinCtx
*r
)
1930 struct cli_state
*cli
= NULL
;
1932 ADS_STATUS ads_status
;
1933 #endif /* WITH_ADS */
1935 if (!r
->in
.dc_name
) {
1936 struct netr_DsRGetDCNameInfo
*info
;
1938 status
= dsgetdcname(mem_ctx
,
1943 DS_FORCE_REDISCOVERY
|
1944 DS_DIRECTORY_SERVICE_REQUIRED
|
1945 DS_WRITABLE_REQUIRED
|
1948 if (!NT_STATUS_IS_OK(status
)) {
1949 libnet_join_set_error_string(mem_ctx
, r
,
1950 "failed to find DC for domain %s",
1952 get_friendly_nt_error_msg(status
));
1953 return WERR_DCNOTFOUND
;
1956 dc
= strip_hostname(info
->dc_unc
);
1957 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
1958 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
1961 status
= libnet_join_lookup_dc_rpc(mem_ctx
, r
, &cli
);
1962 if (!NT_STATUS_IS_OK(status
)) {
1963 libnet_join_set_error_string(mem_ctx
, r
,
1964 "failed to lookup DC info for domain '%s' over rpc: %s",
1965 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
1966 return ntstatus_to_werror(status
);
1969 werr
= libnet_join_check_config(mem_ctx
, r
);
1970 if (!W_ERROR_IS_OK(werr
)) {
1975 if (r
->out
.domain_is_ad
&& r
->in
.account_ou
&&
1976 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1978 ads_status
= libnet_join_connect_ads(mem_ctx
, r
);
1979 if (!ADS_ERR_OK(ads_status
)) {
1980 return WERR_DEFAULT_JOIN_REQUIRED
;
1983 ads_status
= libnet_join_precreate_machine_acct(mem_ctx
, r
);
1984 if (!ADS_ERR_OK(ads_status
)) {
1985 libnet_join_set_error_string(mem_ctx
, r
,
1986 "failed to precreate account in ou %s: %s",
1988 ads_errstr(ads_status
));
1989 return WERR_DEFAULT_JOIN_REQUIRED
;
1992 r
->in
.join_flags
&= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
;
1994 #endif /* WITH_ADS */
1996 if ((r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
) &&
1997 (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED
)) {
1998 status
= libnet_join_joindomain_rpc_unsecure(mem_ctx
, r
, cli
);
2000 status
= libnet_join_joindomain_rpc(mem_ctx
, r
, cli
);
2002 if (!NT_STATUS_IS_OK(status
)) {
2003 libnet_join_set_error_string(mem_ctx
, r
,
2004 "failed to join domain '%s' over rpc: %s",
2005 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
2006 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
2007 return WERR_SETUP_ALREADY_JOINED
;
2009 werr
= ntstatus_to_werror(status
);
2013 if (!libnet_join_joindomain_store_secrets(mem_ctx
, r
)) {
2014 werr
= WERR_SETUP_NOT_JOINED
;
2028 /****************************************************************
2029 ****************************************************************/
2031 static WERROR
libnet_join_rollback(TALLOC_CTX
*mem_ctx
,
2032 struct libnet_JoinCtx
*r
)
2035 struct libnet_UnjoinCtx
*u
= NULL
;
2037 werr
= libnet_init_UnjoinCtx(mem_ctx
, &u
);
2038 if (!W_ERROR_IS_OK(werr
)) {
2042 u
->in
.debug
= r
->in
.debug
;
2043 u
->in
.dc_name
= r
->in
.dc_name
;
2044 u
->in
.domain_name
= r
->in
.domain_name
;
2045 u
->in
.admin_account
= r
->in
.admin_account
;
2046 u
->in
.admin_password
= r
->in
.admin_password
;
2047 u
->in
.modify_config
= r
->in
.modify_config
;
2048 u
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
2049 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
2051 werr
= libnet_Unjoin(mem_ctx
, u
);
2057 /****************************************************************
2058 ****************************************************************/
2060 WERROR
libnet_Join(TALLOC_CTX
*mem_ctx
,
2061 struct libnet_JoinCtx
*r
)
2066 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx
, r
);
2069 werr
= libnet_join_pre_processing(mem_ctx
, r
);
2070 if (!W_ERROR_IS_OK(werr
)) {
2074 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2075 werr
= libnet_DomainJoin(mem_ctx
, r
);
2076 if (!W_ERROR_IS_OK(werr
)) {
2081 werr
= libnet_join_post_processing(mem_ctx
, r
);
2082 if (!W_ERROR_IS_OK(werr
)) {
2086 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2087 werr
= libnet_join_post_verify(mem_ctx
, r
);
2088 if (!W_ERROR_IS_OK(werr
)) {
2089 libnet_join_rollback(mem_ctx
, r
);
2094 r
->out
.result
= werr
;
2097 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx
, r
);
2102 /****************************************************************
2103 ****************************************************************/
2105 static WERROR
libnet_DomainUnjoin(TALLOC_CTX
*mem_ctx
,
2106 struct libnet_UnjoinCtx
*r
)
2110 if (!r
->in
.domain_sid
) {
2112 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid
)) {
2113 libnet_unjoin_set_error_string(mem_ctx
, r
,
2114 "Unable to fetch domain sid: are we joined?");
2115 return WERR_SETUP_NOT_JOINED
;
2117 r
->in
.domain_sid
= dom_sid_dup(mem_ctx
, &sid
);
2118 W_ERROR_HAVE_NO_MEMORY(r
->in
.domain_sid
);
2121 if (!(r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) &&
2122 !r
->in
.delete_machine_account
) {
2123 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2127 if (!r
->in
.dc_name
) {
2128 struct netr_DsRGetDCNameInfo
*info
;
2130 status
= dsgetdcname(mem_ctx
,
2135 DS_DIRECTORY_SERVICE_REQUIRED
|
2136 DS_WRITABLE_REQUIRED
|
2139 if (!NT_STATUS_IS_OK(status
)) {
2140 libnet_unjoin_set_error_string(mem_ctx
, r
,
2141 "failed to find DC for domain %s",
2143 get_friendly_nt_error_msg(status
));
2144 return WERR_DCNOTFOUND
;
2147 dc
= strip_hostname(info
->dc_unc
);
2148 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
2149 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
2153 /* for net ads leave, try to delete the account. If it works,
2154 no sense in disabling. If it fails, we can still try to
2157 if (r
->in
.delete_machine_account
) {
2158 ADS_STATUS ads_status
;
2159 ads_status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
2160 if (ADS_ERR_OK(ads_status
)) {
2162 r
->out
.dns_domain_name
=
2163 talloc_strdup(mem_ctx
,
2164 r
->in
.ads
->server
.realm
);
2166 libnet_unjoin_remove_machine_acct(mem_ctx
, r
);
2168 if (!ADS_ERR_OK(ads_status
)) {
2169 libnet_unjoin_set_error_string(mem_ctx
, r
,
2170 "failed to remove machine account from AD: %s",
2171 ads_errstr(ads_status
));
2173 r
->out
.deleted_machine_account
= true;
2174 W_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
2175 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2179 #endif /* WITH_ADS */
2181 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2183 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) {
2184 status
= libnet_join_unjoindomain_rpc(mem_ctx
, r
);
2185 if (!NT_STATUS_IS_OK(status
)) {
2186 libnet_unjoin_set_error_string(mem_ctx
, r
,
2187 "failed to disable machine account via rpc: %s",
2188 get_friendly_nt_error_msg(status
));
2189 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
2190 return WERR_SETUP_NOT_JOINED
;
2192 return ntstatus_to_werror(status
);
2195 r
->out
.disabled_machine_account
= true;
2198 /* If disable succeeded or was not requested at all, we
2199 should be getting rid of our end of things */
2201 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2206 /****************************************************************
2207 ****************************************************************/
2209 static WERROR
libnet_unjoin_pre_processing(TALLOC_CTX
*mem_ctx
,
2210 struct libnet_UnjoinCtx
*r
)
2212 if (!r
->in
.domain_name
) {
2213 libnet_unjoin_set_error_string(mem_ctx
, r
,
2214 "No domain name defined");
2215 return WERR_INVALID_PARAM
;
2218 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
2221 libnet_unjoin_set_error_string(mem_ctx
, r
,
2222 "Failed to parse domain name");
2223 return WERR_INVALID_PARAM
;
2227 return WERR_SETUP_DOMAIN_CONTROLLER
;
2230 if (!secrets_init()) {
2231 libnet_unjoin_set_error_string(mem_ctx
, r
,
2232 "Unable to open secrets database");
2233 return WERR_CAN_NOT_COMPLETE
;
2239 /****************************************************************
2240 ****************************************************************/
2242 static WERROR
libnet_unjoin_post_processing(TALLOC_CTX
*mem_ctx
,
2243 struct libnet_UnjoinCtx
*r
)
2245 saf_delete(r
->out
.netbios_domain_name
);
2246 saf_delete(r
->out
.dns_domain_name
);
2248 return libnet_unjoin_config(r
);
2251 /****************************************************************
2252 ****************************************************************/
2254 WERROR
libnet_Unjoin(TALLOC_CTX
*mem_ctx
,
2255 struct libnet_UnjoinCtx
*r
)
2260 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx
, r
);
2263 werr
= libnet_unjoin_pre_processing(mem_ctx
, r
);
2264 if (!W_ERROR_IS_OK(werr
)) {
2268 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2269 werr
= libnet_DomainUnjoin(mem_ctx
, r
);
2270 if (!W_ERROR_IS_OK(werr
)) {
2271 libnet_unjoin_config(r
);
2276 werr
= libnet_unjoin_post_processing(mem_ctx
, r
);
2277 if (!W_ERROR_IS_OK(werr
)) {
2282 r
->out
.result
= werr
;
2285 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx
, r
);