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"
37 #include "rpc_client/cli_pipe.h"
38 #include "../libcli/security/security.h"
40 #include "libsmb/libsmb.h"
41 #include "../libcli/smb/smbXcli_base.h"
42 #include "lib/param/loadparm.h"
44 /****************************************************************
45 ****************************************************************/
47 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
50 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
51 DEBUG(1,("libnet_Join:\n%s", str)); \
55 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
56 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
57 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
58 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
60 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
63 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
64 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
68 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
69 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
70 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
71 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
73 /****************************************************************
74 ****************************************************************/
76 static void libnet_join_set_error_string(TALLOC_CTX
*mem_ctx
,
77 struct libnet_JoinCtx
*r
,
78 const char *format
, ...)
82 if (r
->out
.error_string
) {
86 va_start(args
, format
);
87 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
91 /****************************************************************
92 ****************************************************************/
94 static void libnet_unjoin_set_error_string(TALLOC_CTX
*mem_ctx
,
95 struct libnet_UnjoinCtx
*r
,
96 const char *format
, ...)
100 if (r
->out
.error_string
) {
104 va_start(args
, format
);
105 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
111 /****************************************************************
112 ****************************************************************/
114 static ADS_STATUS
libnet_connect_ads(const char *dns_domain_name
,
115 const char *netbios_domain_name
,
117 const char *user_name
,
118 const char *password
,
122 ADS_STRUCT
*my_ads
= NULL
;
125 my_ads
= ads_init(dns_domain_name
,
129 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
133 SAFE_FREE(my_ads
->auth
.user_name
);
134 my_ads
->auth
.user_name
= SMB_STRDUP(user_name
);
135 if ((cp
= strchr_m(my_ads
->auth
.user_name
, '@'))!=0) {
137 SAFE_FREE(my_ads
->auth
.realm
);
138 my_ads
->auth
.realm
= smb_xstrdup(cp
);
139 if (!strupper_m(my_ads
->auth
.realm
)) {
140 ads_destroy(&my_ads
);
141 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
147 SAFE_FREE(my_ads
->auth
.password
);
148 my_ads
->auth
.password
= SMB_STRDUP(password
);
151 status
= ads_connect_user_creds(my_ads
);
152 if (!ADS_ERR_OK(status
)) {
153 ads_destroy(&my_ads
);
161 /****************************************************************
162 ****************************************************************/
164 static ADS_STATUS
libnet_join_connect_ads(TALLOC_CTX
*mem_ctx
,
165 struct libnet_JoinCtx
*r
)
169 status
= libnet_connect_ads(r
->out
.dns_domain_name
,
170 r
->out
.netbios_domain_name
,
173 r
->in
.admin_password
,
175 if (!ADS_ERR_OK(status
)) {
176 libnet_join_set_error_string(mem_ctx
, r
,
177 "failed to connect to AD: %s",
182 if (!r
->out
.netbios_domain_name
) {
183 r
->out
.netbios_domain_name
= talloc_strdup(mem_ctx
,
184 r
->in
.ads
->server
.workgroup
);
185 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.netbios_domain_name
);
188 if (!r
->out
.dns_domain_name
) {
189 r
->out
.dns_domain_name
= talloc_strdup(mem_ctx
,
190 r
->in
.ads
->config
.realm
);
191 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
194 r
->out
.domain_is_ad
= true;
199 /****************************************************************
200 ****************************************************************/
202 static ADS_STATUS
libnet_unjoin_connect_ads(TALLOC_CTX
*mem_ctx
,
203 struct libnet_UnjoinCtx
*r
)
207 status
= libnet_connect_ads(r
->in
.domain_name
,
211 r
->in
.admin_password
,
213 if (!ADS_ERR_OK(status
)) {
214 libnet_unjoin_set_error_string(mem_ctx
, r
,
215 "failed to connect to AD: %s",
222 /****************************************************************
223 join a domain using ADS (LDAP mods)
224 ****************************************************************/
226 static ADS_STATUS
libnet_join_precreate_machine_acct(TALLOC_CTX
*mem_ctx
,
227 struct libnet_JoinCtx
*r
)
230 LDAPMessage
*res
= NULL
;
231 const char *attrs
[] = { "dn", NULL
};
234 status
= ads_check_ou_dn(mem_ctx
, r
->in
.ads
, &r
->in
.account_ou
);
235 if (!ADS_ERR_OK(status
)) {
239 status
= ads_search_dn(r
->in
.ads
, &res
, r
->in
.account_ou
, attrs
);
240 if (!ADS_ERR_OK(status
)) {
244 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
245 ads_msgfree(r
->in
.ads
, res
);
246 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT
);
249 ads_msgfree(r
->in
.ads
, res
);
251 /* Attempt to create the machine account and bail if this fails.
252 Assume that the admin wants exactly what they requested */
254 status
= ads_create_machine_acct(r
->in
.ads
,
258 if (ADS_ERR_OK(status
)) {
259 DEBUG(1,("machine account creation created\n"));
261 } else if ((status
.error_type
== ENUM_ADS_ERROR_LDAP
) &&
262 (status
.err
.rc
== LDAP_ALREADY_EXISTS
)) {
263 status
= ADS_SUCCESS
;
266 if (!ADS_ERR_OK(status
)) {
267 DEBUG(1,("machine account creation failed\n"));
271 status
= ads_move_machine_acct(r
->in
.ads
,
275 if (!ADS_ERR_OK(status
)) {
276 DEBUG(1,("failure to locate/move pre-existing "
277 "machine account\n"));
281 DEBUG(1,("The machine account %s the specified OU.\n",
282 moved
? "was moved into" : "already exists in"));
287 /****************************************************************
288 ****************************************************************/
290 static ADS_STATUS
libnet_unjoin_remove_machine_acct(TALLOC_CTX
*mem_ctx
,
291 struct libnet_UnjoinCtx
*r
)
296 status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
297 if (!ADS_ERR_OK(status
)) {
298 libnet_unjoin_set_error_string(mem_ctx
, r
,
299 "failed to connect to AD: %s",
305 status
= ads_leave_realm(r
->in
.ads
, r
->in
.machine_name
);
306 if (!ADS_ERR_OK(status
)) {
307 libnet_unjoin_set_error_string(mem_ctx
, r
,
308 "failed to leave realm: %s",
316 /****************************************************************
317 ****************************************************************/
319 static ADS_STATUS
libnet_join_find_machine_acct(TALLOC_CTX
*mem_ctx
,
320 struct libnet_JoinCtx
*r
)
323 LDAPMessage
*res
= NULL
;
326 if (!r
->in
.machine_name
) {
327 return ADS_ERROR(LDAP_NO_MEMORY
);
330 status
= ads_find_machine_acct(r
->in
.ads
,
333 if (!ADS_ERR_OK(status
)) {
337 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
338 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
342 dn
= ads_get_dn(r
->in
.ads
, mem_ctx
, res
);
344 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
348 r
->out
.dn
= talloc_strdup(mem_ctx
, dn
);
350 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
355 ads_msgfree(r
->in
.ads
, res
);
361 /****************************************************************
362 Set a machines dNSHostName and servicePrincipalName attributes
363 ****************************************************************/
365 static ADS_STATUS
libnet_join_set_machine_spn(TALLOC_CTX
*mem_ctx
,
366 struct libnet_JoinCtx
*r
)
371 const char *spn_array
[3] = {NULL
, NULL
, NULL
};
376 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
377 if (!ADS_ERR_OK(status
)) {
381 /* Windows only creates HOST/shortname & HOST/fqdn. */
383 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", r
->in
.machine_name
);
385 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
387 if (!strupper_m(spn
)) {
388 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
392 if (!name_to_fqdn(my_fqdn
, r
->in
.machine_name
)
393 || (strchr(my_fqdn
, '.') == NULL
)) {
394 fstr_sprintf(my_fqdn
, "%s.%s", r
->in
.machine_name
,
395 r
->out
.dns_domain_name
);
398 if (!strlower_m(my_fqdn
)) {
399 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
402 if (!strequal(my_fqdn
, r
->in
.machine_name
)) {
403 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", my_fqdn
);
405 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
410 mods
= ads_init_mods(mem_ctx
);
412 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
415 /* fields of primary importance */
417 status
= ads_mod_str(mem_ctx
, &mods
, "dNSHostName", my_fqdn
);
418 if (!ADS_ERR_OK(status
)) {
419 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
422 status
= ads_mod_strlist(mem_ctx
, &mods
, "servicePrincipalName",
424 if (!ADS_ERR_OK(status
)) {
425 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
428 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
431 /****************************************************************
432 ****************************************************************/
434 static ADS_STATUS
libnet_join_set_machine_upn(TALLOC_CTX
*mem_ctx
,
435 struct libnet_JoinCtx
*r
)
440 if (!r
->in
.create_upn
) {
446 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
447 if (!ADS_ERR_OK(status
)) {
452 const char *realm
= r
->out
.dns_domain_name
;
454 /* in case we are about to generate a keytab during the join
455 * make sure the default upn we create is usable with kinit -k.
458 if (USE_KERBEROS_KEYTAB
) {
459 realm
= talloc_strdup_upper(mem_ctx
,
460 r
->out
.dns_domain_name
);
464 return ADS_ERROR(LDAP_NO_MEMORY
);
467 r
->in
.upn
= talloc_asprintf(mem_ctx
,
472 return ADS_ERROR(LDAP_NO_MEMORY
);
476 /* now do the mods */
478 mods
= ads_init_mods(mem_ctx
);
480 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
483 /* fields of primary importance */
485 status
= ads_mod_str(mem_ctx
, &mods
, "userPrincipalName", r
->in
.upn
);
486 if (!ADS_ERR_OK(status
)) {
487 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
490 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
494 /****************************************************************
495 ****************************************************************/
497 static ADS_STATUS
libnet_join_set_os_attributes(TALLOC_CTX
*mem_ctx
,
498 struct libnet_JoinCtx
*r
)
504 if (!r
->in
.os_name
|| !r
->in
.os_version
) {
510 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
511 if (!ADS_ERR_OK(status
)) {
515 /* now do the mods */
517 mods
= ads_init_mods(mem_ctx
);
519 return ADS_ERROR(LDAP_NO_MEMORY
);
522 os_sp
= talloc_asprintf(mem_ctx
, "Samba %s", samba_version_string());
524 return ADS_ERROR(LDAP_NO_MEMORY
);
527 /* fields of primary importance */
529 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystem",
531 if (!ADS_ERR_OK(status
)) {
535 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemVersion",
537 if (!ADS_ERR_OK(status
)) {
541 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemServicePack",
543 if (!ADS_ERR_OK(status
)) {
547 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
550 /****************************************************************
551 ****************************************************************/
553 static bool libnet_join_create_keytab(TALLOC_CTX
*mem_ctx
,
554 struct libnet_JoinCtx
*r
)
556 if (!USE_SYSTEM_KEYTAB
) {
560 if (ads_keytab_create_default(r
->in
.ads
) != 0) {
567 /****************************************************************
568 ****************************************************************/
570 static bool libnet_join_derive_salting_principal(TALLOC_CTX
*mem_ctx
,
571 struct libnet_JoinCtx
*r
)
573 uint32_t domain_func
;
575 const char *salt
= NULL
;
576 char *std_salt
= NULL
;
578 status
= ads_domain_func_level(r
->in
.ads
, &domain_func
);
579 if (!ADS_ERR_OK(status
)) {
580 libnet_join_set_error_string(mem_ctx
, r
,
581 "failed to determine domain functional level: %s",
586 /* go ahead and setup the default salt */
588 std_salt
= kerberos_standard_des_salt();
590 libnet_join_set_error_string(mem_ctx
, r
,
591 "failed to obtain standard DES salt");
595 salt
= talloc_strdup(mem_ctx
, std_salt
);
602 /* if it's a Windows functional domain, we have to look for the UPN */
604 if (domain_func
== DS_DOMAIN_FUNCTION_2000
) {
607 upn
= ads_get_upn(r
->in
.ads
, mem_ctx
,
610 salt
= talloc_strdup(mem_ctx
, upn
);
617 return kerberos_secrets_store_des_salt(salt
);
620 /****************************************************************
621 ****************************************************************/
623 static ADS_STATUS
libnet_join_post_processing_ads(TALLOC_CTX
*mem_ctx
,
624 struct libnet_JoinCtx
*r
)
629 status
= libnet_join_connect_ads(mem_ctx
, r
);
630 if (!ADS_ERR_OK(status
)) {
635 status
= libnet_join_set_machine_spn(mem_ctx
, r
);
636 if (!ADS_ERR_OK(status
)) {
637 libnet_join_set_error_string(mem_ctx
, r
,
638 "failed to set machine spn: %s",
643 status
= libnet_join_set_os_attributes(mem_ctx
, r
);
644 if (!ADS_ERR_OK(status
)) {
645 libnet_join_set_error_string(mem_ctx
, r
,
646 "failed to set machine os attributes: %s",
651 status
= libnet_join_set_machine_upn(mem_ctx
, r
);
652 if (!ADS_ERR_OK(status
)) {
653 libnet_join_set_error_string(mem_ctx
, r
,
654 "failed to set machine upn: %s",
659 if (!libnet_join_derive_salting_principal(mem_ctx
, r
)) {
660 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
663 if (!libnet_join_create_keytab(mem_ctx
, r
)) {
664 libnet_join_set_error_string(mem_ctx
, r
,
665 "failed to create kerberos keytab");
666 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
671 #endif /* HAVE_ADS */
673 /****************************************************************
674 Store the machine password and domain SID
675 ****************************************************************/
677 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX
*mem_ctx
,
678 struct libnet_JoinCtx
*r
)
680 if (!secrets_store_domain_sid(r
->out
.netbios_domain_name
,
683 DEBUG(1,("Failed to save domain sid\n"));
687 if (!secrets_store_machine_password(r
->in
.machine_password
,
688 r
->out
.netbios_domain_name
,
689 r
->in
.secure_channel_type
))
691 DEBUG(1,("Failed to save machine password\n"));
698 /****************************************************************
699 Connect dc's IPC$ share
700 ****************************************************************/
702 static NTSTATUS
libnet_join_connect_dc_ipc(const char *dc
,
706 struct cli_state
**cli
)
711 flags
|= CLI_FULL_CONNECTION_USE_KERBEROS
;
714 if (use_kerberos
&& pass
) {
715 flags
|= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS
;
718 return cli_full_connection(cli
, NULL
,
726 SMB_SIGNING_DEFAULT
);
729 /****************************************************************
730 Lookup domain dc's info
731 ****************************************************************/
733 static NTSTATUS
libnet_join_lookup_dc_rpc(TALLOC_CTX
*mem_ctx
,
734 struct libnet_JoinCtx
*r
,
735 struct cli_state
**cli
)
737 struct rpc_pipe_client
*pipe_hnd
= NULL
;
738 struct policy_handle lsa_pol
;
739 NTSTATUS status
, result
;
740 union lsa_PolicyInformation
*info
= NULL
;
741 struct dcerpc_binding_handle
*b
;
743 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
745 r
->in
.admin_password
,
748 if (!NT_STATUS_IS_OK(status
)) {
752 status
= cli_rpc_pipe_open_noauth(*cli
, &ndr_table_lsarpc
.syntax_id
,
754 if (!NT_STATUS_IS_OK(status
)) {
755 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
760 b
= pipe_hnd
->binding_handle
;
762 status
= rpccli_lsa_open_policy(pipe_hnd
, mem_ctx
, true,
763 SEC_FLAG_MAXIMUM_ALLOWED
, &lsa_pol
);
764 if (!NT_STATUS_IS_OK(status
)) {
768 status
= dcerpc_lsa_QueryInfoPolicy2(b
, mem_ctx
,
773 if (NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(result
)) {
774 r
->out
.domain_is_ad
= true;
775 r
->out
.netbios_domain_name
= info
->dns
.name
.string
;
776 r
->out
.dns_domain_name
= info
->dns
.dns_domain
.string
;
777 r
->out
.forest_name
= info
->dns
.dns_forest
.string
;
778 r
->out
.domain_sid
= dom_sid_dup(mem_ctx
, info
->dns
.sid
);
779 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
782 if (!NT_STATUS_IS_OK(status
)) {
783 status
= dcerpc_lsa_QueryInfoPolicy(b
, mem_ctx
,
785 LSA_POLICY_INFO_ACCOUNT_DOMAIN
,
788 if (!NT_STATUS_IS_OK(status
)) {
791 if (!NT_STATUS_IS_OK(result
)) {
796 r
->out
.netbios_domain_name
= info
->account_domain
.name
.string
;
797 r
->out
.domain_sid
= dom_sid_dup(mem_ctx
, info
->account_domain
.sid
);
798 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
801 dcerpc_lsa_Close(b
, mem_ctx
, &lsa_pol
, &result
);
802 TALLOC_FREE(pipe_hnd
);
808 /****************************************************************
809 Do the domain join unsecure
810 ****************************************************************/
812 static NTSTATUS
libnet_join_joindomain_rpc_unsecure(TALLOC_CTX
*mem_ctx
,
813 struct libnet_JoinCtx
*r
,
814 struct cli_state
*cli
)
816 struct rpc_pipe_client
*pipe_hnd
= NULL
;
817 unsigned char orig_trust_passwd_hash
[16];
818 unsigned char new_trust_passwd_hash
[16];
819 fstring trust_passwd
;
822 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_netlogon
.syntax_id
,
824 if (!NT_STATUS_IS_OK(status
)) {
828 if (!r
->in
.machine_password
) {
829 r
->in
.machine_password
= generate_random_password(mem_ctx
,
830 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
,
831 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
832 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
835 E_md4hash(r
->in
.machine_password
, new_trust_passwd_hash
);
837 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
838 fstrcpy(trust_passwd
, r
->in
.admin_password
);
839 if (!strlower_m(trust_passwd
)) {
840 return NT_STATUS_INVALID_PARAMETER
;
844 * Machine names can be 15 characters, but the max length on
845 * a password is 14. --jerry
848 trust_passwd
[14] = '\0';
850 E_md4hash(trust_passwd
, orig_trust_passwd_hash
);
852 status
= rpccli_netlogon_set_trust_password(pipe_hnd
, mem_ctx
,
854 orig_trust_passwd_hash
,
855 r
->in
.machine_password
,
856 new_trust_passwd_hash
,
857 r
->in
.secure_channel_type
);
862 /****************************************************************
864 ****************************************************************/
866 static NTSTATUS
libnet_join_joindomain_rpc(TALLOC_CTX
*mem_ctx
,
867 struct libnet_JoinCtx
*r
,
868 struct cli_state
*cli
)
870 struct rpc_pipe_client
*pipe_hnd
= NULL
;
871 struct policy_handle sam_pol
, domain_pol
, user_pol
;
872 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
, result
;
874 struct lsa_String lsa_acct_name
;
876 uint32_t acct_flags
= ACB_WSTRUST
;
877 struct samr_Ids user_rids
;
878 struct samr_Ids name_types
;
879 union samr_UserInfo user_info
;
880 struct dcerpc_binding_handle
*b
= NULL
;
881 unsigned int old_timeout
= 0;
883 DATA_BLOB session_key
= data_blob_null
;
884 struct samr_CryptPassword crypt_pwd
;
885 struct samr_CryptPasswordEx crypt_pwd_ex
;
887 ZERO_STRUCT(sam_pol
);
888 ZERO_STRUCT(domain_pol
);
889 ZERO_STRUCT(user_pol
);
891 switch (r
->in
.secure_channel_type
) {
893 acct_flags
= ACB_WSTRUST
;
896 acct_flags
= ACB_SVRTRUST
;
899 return NT_STATUS_INVALID_PARAMETER
;
902 if (!r
->in
.machine_password
) {
903 r
->in
.machine_password
= generate_random_password(mem_ctx
,
904 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
,
905 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
906 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
909 /* Open the domain */
911 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
913 if (!NT_STATUS_IS_OK(status
)) {
914 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
919 b
= pipe_hnd
->binding_handle
;
921 status
= cli_get_session_key(mem_ctx
, pipe_hnd
, &session_key
);
922 if (!NT_STATUS_IS_OK(status
)) {
923 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
928 status
= dcerpc_samr_Connect2(b
, mem_ctx
,
930 SAMR_ACCESS_ENUM_DOMAINS
931 | SAMR_ACCESS_LOOKUP_DOMAIN
,
934 if (!NT_STATUS_IS_OK(status
)) {
937 if (!NT_STATUS_IS_OK(result
)) {
942 status
= dcerpc_samr_OpenDomain(b
, mem_ctx
,
944 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
945 | SAMR_DOMAIN_ACCESS_CREATE_USER
946 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT
,
950 if (!NT_STATUS_IS_OK(status
)) {
953 if (!NT_STATUS_IS_OK(result
)) {
958 /* Create domain user */
960 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
961 if (!strlower_m(acct_name
)) {
962 status
= NT_STATUS_INVALID_PARAMETER
;
966 init_lsa_String(&lsa_acct_name
, acct_name
);
968 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
) {
969 uint32_t access_desired
=
970 SEC_GENERIC_READ
| SEC_GENERIC_WRITE
| SEC_GENERIC_EXECUTE
|
971 SEC_STD_WRITE_DAC
| SEC_STD_DELETE
|
972 SAMR_USER_ACCESS_SET_PASSWORD
|
973 SAMR_USER_ACCESS_GET_ATTRIBUTES
|
974 SAMR_USER_ACCESS_SET_ATTRIBUTES
;
975 uint32_t access_granted
= 0;
977 DEBUG(10,("Creating account with desired access mask: %d\n",
980 status
= dcerpc_samr_CreateUser2(b
, mem_ctx
,
989 if (!NT_STATUS_IS_OK(status
)) {
994 if (!NT_STATUS_IS_OK(status
) &&
995 !NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
997 DEBUG(10,("Creation of workstation account failed: %s\n",
1000 /* If NT_STATUS_ACCESS_DENIED then we have a valid
1001 username/password combo but the user does not have
1002 administrator access. */
1004 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1005 libnet_join_set_error_string(mem_ctx
, r
,
1006 "User specified does not have "
1007 "administrator privileges");
1013 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
1014 if (!(r
->in
.join_flags
&
1015 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
)) {
1020 /* We *must* do this.... don't ask... */
1022 if (NT_STATUS_IS_OK(status
)) {
1023 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1027 status
= dcerpc_samr_LookupNames(b
, mem_ctx
,
1034 if (!NT_STATUS_IS_OK(status
)) {
1037 if (!NT_STATUS_IS_OK(result
)) {
1041 if (user_rids
.count
!= 1) {
1042 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1045 if (name_types
.count
!= 1) {
1046 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1050 if (name_types
.ids
[0] != SID_NAME_USER
) {
1051 DEBUG(0,("%s is not a user account (type=%d)\n",
1052 acct_name
, name_types
.ids
[0]));
1053 status
= NT_STATUS_INVALID_WORKSTATION
;
1057 user_rid
= user_rids
.ids
[0];
1059 /* Open handle on user */
1061 status
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1063 SEC_FLAG_MAXIMUM_ALLOWED
,
1067 if (!NT_STATUS_IS_OK(status
)) {
1070 if (!NT_STATUS_IS_OK(result
)) {
1075 /* Fill in the additional account flags now */
1077 acct_flags
|= ACB_PWNOEXP
;
1079 /* Set account flags on machine account */
1080 ZERO_STRUCT(user_info
.info16
);
1081 user_info
.info16
.acct_flags
= acct_flags
;
1083 status
= dcerpc_samr_SetUserInfo(b
, mem_ctx
,
1088 if (!NT_STATUS_IS_OK(status
)) {
1089 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1093 libnet_join_set_error_string(mem_ctx
, r
,
1094 "Failed to set account flags for machine account (%s)\n",
1099 if (!NT_STATUS_IS_OK(result
)) {
1102 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1106 libnet_join_set_error_string(mem_ctx
, r
,
1107 "Failed to set account flags for machine account (%s)\n",
1112 /* Set password on machine account - first try level 26 */
1115 * increase the timeout as password filter modules on the DC
1116 * might delay the operation for a significant amount of time
1118 old_timeout
= rpccli_set_timeout(pipe_hnd
, 600000);
1120 init_samr_CryptPasswordEx(r
->in
.machine_password
,
1124 user_info
.info26
.password
= crypt_pwd_ex
;
1125 user_info
.info26
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1127 status
= dcerpc_samr_SetUserInfo2(b
, mem_ctx
,
1133 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
)) {
1135 /* retry with level 24 */
1137 init_samr_CryptPassword(r
->in
.machine_password
,
1141 user_info
.info24
.password
= crypt_pwd
;
1142 user_info
.info24
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1144 status
= dcerpc_samr_SetUserInfo2(b
, mem_ctx
,
1151 old_timeout
= rpccli_set_timeout(pipe_hnd
, old_timeout
);
1153 if (!NT_STATUS_IS_OK(status
)) {
1155 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1159 libnet_join_set_error_string(mem_ctx
, r
,
1160 "Failed to set password for machine account (%s)\n",
1164 if (!NT_STATUS_IS_OK(result
)) {
1167 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1171 libnet_join_set_error_string(mem_ctx
, r
,
1172 "Failed to set password for machine account (%s)\n",
1177 status
= NT_STATUS_OK
;
1184 data_blob_clear_free(&session_key
);
1186 if (is_valid_policy_hnd(&sam_pol
)) {
1187 dcerpc_samr_Close(b
, mem_ctx
, &sam_pol
, &result
);
1189 if (is_valid_policy_hnd(&domain_pol
)) {
1190 dcerpc_samr_Close(b
, mem_ctx
, &domain_pol
, &result
);
1192 if (is_valid_policy_hnd(&user_pol
)) {
1193 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1195 TALLOC_FREE(pipe_hnd
);
1200 /****************************************************************
1201 ****************************************************************/
1203 NTSTATUS
libnet_join_ok(const char *netbios_domain_name
,
1204 const char *machine_name
,
1205 const char *dc_name
,
1206 const bool use_kerberos
)
1208 uint32_t neg_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
1209 struct cli_state
*cli
= NULL
;
1210 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1211 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1213 char *machine_password
= NULL
;
1214 char *machine_account
= NULL
;
1218 return NT_STATUS_INVALID_PARAMETER
;
1221 if (!secrets_init()) {
1222 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1225 machine_password
= secrets_fetch_machine_password(netbios_domain_name
,
1227 if (!machine_password
) {
1228 return NT_STATUS_NO_TRUST_LSA_SECRET
;
1231 if (asprintf(&machine_account
, "%s$", machine_name
) == -1) {
1232 SAFE_FREE(machine_password
);
1233 return NT_STATUS_NO_MEMORY
;
1237 flags
|= CLI_FULL_CONNECTION_USE_KERBEROS
;
1240 status
= cli_full_connection(&cli
, NULL
,
1248 SMB_SIGNING_DEFAULT
);
1249 free(machine_account
);
1250 free(machine_password
);
1252 if (!NT_STATUS_IS_OK(status
)) {
1253 status
= cli_full_connection(&cli
, NULL
,
1261 SMB_SIGNING_DEFAULT
);
1264 if (!NT_STATUS_IS_OK(status
)) {
1268 status
= get_schannel_session_key(cli
, netbios_domain_name
,
1269 &neg_flags
, &netlogon_pipe
);
1270 if (!NT_STATUS_IS_OK(status
)) {
1271 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_NETWORK_RESPONSE
)) {
1273 return NT_STATUS_OK
;
1276 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1277 "key from server %s for domain %s. Error was %s\n",
1278 smbXcli_conn_remote_name(cli
->conn
),
1279 netbios_domain_name
, nt_errstr(status
)));
1284 if (!lp_client_schannel()) {
1286 return NT_STATUS_OK
;
1289 status
= cli_rpc_pipe_open_schannel_with_key(
1290 cli
, &ndr_table_netlogon
.syntax_id
, NCACN_NP
,
1291 DCERPC_AUTH_LEVEL_PRIVACY
,
1292 netbios_domain_name
, &netlogon_pipe
->dc
, &pipe_hnd
);
1296 if (!NT_STATUS_IS_OK(status
)) {
1297 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1298 "on netlogon pipe to server %s for domain %s. "
1300 smbXcli_conn_remote_name(cli
->conn
),
1301 netbios_domain_name
, nt_errstr(status
)));
1305 return NT_STATUS_OK
;
1308 /****************************************************************
1309 ****************************************************************/
1311 static WERROR
libnet_join_post_verify(TALLOC_CTX
*mem_ctx
,
1312 struct libnet_JoinCtx
*r
)
1316 status
= libnet_join_ok(r
->out
.netbios_domain_name
,
1319 r
->in
.use_kerberos
);
1320 if (!NT_STATUS_IS_OK(status
)) {
1321 libnet_join_set_error_string(mem_ctx
, r
,
1322 "failed to verify domain membership after joining: %s",
1323 get_friendly_nt_error_msg(status
));
1324 return WERR_SETUP_NOT_JOINED
;
1330 /****************************************************************
1331 ****************************************************************/
1333 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX
*mem_ctx
,
1334 struct libnet_UnjoinCtx
*r
)
1336 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1340 if (!secrets_delete_domain_sid(lp_workgroup())) {
1347 /****************************************************************
1348 ****************************************************************/
1350 static NTSTATUS
libnet_join_unjoindomain_rpc(TALLOC_CTX
*mem_ctx
,
1351 struct libnet_UnjoinCtx
*r
)
1353 struct cli_state
*cli
= NULL
;
1354 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1355 struct policy_handle sam_pol
, domain_pol
, user_pol
;
1356 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
, result
;
1359 struct lsa_String lsa_acct_name
;
1360 struct samr_Ids user_rids
;
1361 struct samr_Ids name_types
;
1362 union samr_UserInfo
*info
= NULL
;
1363 struct dcerpc_binding_handle
*b
= NULL
;
1365 ZERO_STRUCT(sam_pol
);
1366 ZERO_STRUCT(domain_pol
);
1367 ZERO_STRUCT(user_pol
);
1369 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
1370 r
->in
.admin_account
,
1371 r
->in
.admin_password
,
1374 if (!NT_STATUS_IS_OK(status
)) {
1378 /* Open the domain */
1380 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
1382 if (!NT_STATUS_IS_OK(status
)) {
1383 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1384 nt_errstr(status
)));
1388 b
= pipe_hnd
->binding_handle
;
1390 status
= dcerpc_samr_Connect2(b
, mem_ctx
,
1392 SEC_FLAG_MAXIMUM_ALLOWED
,
1395 if (!NT_STATUS_IS_OK(status
)) {
1398 if (!NT_STATUS_IS_OK(result
)) {
1403 status
= dcerpc_samr_OpenDomain(b
, mem_ctx
,
1405 SEC_FLAG_MAXIMUM_ALLOWED
,
1409 if (!NT_STATUS_IS_OK(status
)) {
1412 if (!NT_STATUS_IS_OK(result
)) {
1417 /* Create domain user */
1419 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
1420 if (!strlower_m(acct_name
)) {
1421 status
= NT_STATUS_INVALID_PARAMETER
;
1425 init_lsa_String(&lsa_acct_name
, acct_name
);
1427 status
= dcerpc_samr_LookupNames(b
, mem_ctx
,
1435 if (!NT_STATUS_IS_OK(status
)) {
1438 if (!NT_STATUS_IS_OK(result
)) {
1442 if (user_rids
.count
!= 1) {
1443 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1446 if (name_types
.count
!= 1) {
1447 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1451 if (name_types
.ids
[0] != SID_NAME_USER
) {
1452 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name
,
1453 name_types
.ids
[0]));
1454 status
= NT_STATUS_INVALID_WORKSTATION
;
1458 user_rid
= user_rids
.ids
[0];
1460 /* Open handle on user */
1462 status
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1464 SEC_FLAG_MAXIMUM_ALLOWED
,
1468 if (!NT_STATUS_IS_OK(status
)) {
1471 if (!NT_STATUS_IS_OK(result
)) {
1478 status
= dcerpc_samr_QueryUserInfo(b
, mem_ctx
,
1483 if (!NT_STATUS_IS_OK(status
)) {
1484 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1487 if (!NT_STATUS_IS_OK(result
)) {
1489 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1493 /* now disable and setuser info */
1495 info
->info16
.acct_flags
|= ACB_DISABLED
;
1497 status
= dcerpc_samr_SetUserInfo(b
, mem_ctx
,
1502 if (!NT_STATUS_IS_OK(status
)) {
1503 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1506 if (!NT_STATUS_IS_OK(result
)) {
1508 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1512 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1515 if (pipe_hnd
&& b
) {
1516 if (is_valid_policy_hnd(&domain_pol
)) {
1517 dcerpc_samr_Close(b
, mem_ctx
, &domain_pol
, &result
);
1519 if (is_valid_policy_hnd(&sam_pol
)) {
1520 dcerpc_samr_Close(b
, mem_ctx
, &sam_pol
, &result
);
1522 TALLOC_FREE(pipe_hnd
);
1532 /****************************************************************
1533 ****************************************************************/
1535 static WERROR
do_join_modify_vals_config(struct libnet_JoinCtx
*r
)
1537 WERROR werr
= WERR_OK
;
1539 struct smbconf_ctx
*ctx
;
1541 err
= smbconf_init_reg(r
, &ctx
, NULL
);
1542 if (!SBC_ERROR_IS_OK(err
)) {
1543 werr
= WERR_NO_SUCH_SERVICE
;
1547 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1549 err
= smbconf_set_global_parameter(ctx
, "security", "user");
1550 if (!SBC_ERROR_IS_OK(err
)) {
1551 werr
= WERR_NO_SUCH_SERVICE
;
1555 err
= smbconf_set_global_parameter(ctx
, "workgroup",
1557 if (!SBC_ERROR_IS_OK(err
)) {
1558 werr
= WERR_NO_SUCH_SERVICE
;
1562 smbconf_delete_global_parameter(ctx
, "realm");
1566 err
= smbconf_set_global_parameter(ctx
, "security", "domain");
1567 if (!SBC_ERROR_IS_OK(err
)) {
1568 werr
= WERR_NO_SUCH_SERVICE
;
1572 err
= smbconf_set_global_parameter(ctx
, "workgroup",
1573 r
->out
.netbios_domain_name
);
1574 if (!SBC_ERROR_IS_OK(err
)) {
1575 werr
= WERR_NO_SUCH_SERVICE
;
1579 if (r
->out
.domain_is_ad
) {
1580 err
= smbconf_set_global_parameter(ctx
, "security", "ads");
1581 if (!SBC_ERROR_IS_OK(err
)) {
1582 werr
= WERR_NO_SUCH_SERVICE
;
1586 err
= smbconf_set_global_parameter(ctx
, "realm",
1587 r
->out
.dns_domain_name
);
1588 if (!SBC_ERROR_IS_OK(err
)) {
1589 werr
= WERR_NO_SUCH_SERVICE
;
1595 smbconf_shutdown(ctx
);
1599 /****************************************************************
1600 ****************************************************************/
1602 static WERROR
do_unjoin_modify_vals_config(struct libnet_UnjoinCtx
*r
)
1604 WERROR werr
= WERR_OK
;
1606 struct smbconf_ctx
*ctx
;
1608 err
= smbconf_init_reg(r
, &ctx
, NULL
);
1609 if (!SBC_ERROR_IS_OK(err
)) {
1610 werr
= WERR_NO_SUCH_SERVICE
;
1614 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1616 err
= smbconf_set_global_parameter(ctx
, "security", "user");
1617 if (!SBC_ERROR_IS_OK(err
)) {
1618 werr
= WERR_NO_SUCH_SERVICE
;
1622 err
= smbconf_delete_global_parameter(ctx
, "workgroup");
1623 if (!SBC_ERROR_IS_OK(err
)) {
1624 werr
= WERR_NO_SUCH_SERVICE
;
1628 smbconf_delete_global_parameter(ctx
, "realm");
1632 smbconf_shutdown(ctx
);
1636 /****************************************************************
1637 ****************************************************************/
1639 static WERROR
do_JoinConfig(struct libnet_JoinCtx
*r
)
1643 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1644 return r
->out
.result
;
1647 if (!r
->in
.modify_config
) {
1651 werr
= do_join_modify_vals_config(r
);
1652 if (!W_ERROR_IS_OK(werr
)) {
1656 lp_load_global(get_dyn_CONFIGFILE());
1658 r
->out
.modified_config
= true;
1659 r
->out
.result
= werr
;
1664 /****************************************************************
1665 ****************************************************************/
1667 static WERROR
libnet_unjoin_config(struct libnet_UnjoinCtx
*r
)
1671 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1672 return r
->out
.result
;
1675 if (!r
->in
.modify_config
) {
1679 werr
= do_unjoin_modify_vals_config(r
);
1680 if (!W_ERROR_IS_OK(werr
)) {
1684 lp_load_global(get_dyn_CONFIGFILE());
1686 r
->out
.modified_config
= true;
1687 r
->out
.result
= werr
;
1692 /****************************************************************
1693 ****************************************************************/
1695 static bool libnet_parse_domain_dc(TALLOC_CTX
*mem_ctx
,
1696 const char *domain_str
,
1697 const char **domain_p
,
1700 char *domain
= NULL
;
1702 const char *p
= NULL
;
1704 if (!domain_str
|| !domain_p
|| !dc_p
) {
1708 p
= strchr_m(domain_str
, '\\');
1711 domain
= talloc_strndup(mem_ctx
, domain_str
,
1712 PTR_DIFF(p
, domain_str
));
1713 dc
= talloc_strdup(mem_ctx
, p
+1);
1718 domain
= talloc_strdup(mem_ctx
, domain_str
);
1734 /****************************************************************
1735 ****************************************************************/
1737 static WERROR
libnet_join_pre_processing(TALLOC_CTX
*mem_ctx
,
1738 struct libnet_JoinCtx
*r
)
1740 if (!r
->in
.domain_name
) {
1741 libnet_join_set_error_string(mem_ctx
, r
,
1742 "No domain name defined");
1743 return WERR_INVALID_PARAM
;
1746 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
1749 libnet_join_set_error_string(mem_ctx
, r
,
1750 "Failed to parse domain name");
1751 return WERR_INVALID_PARAM
;
1755 return WERR_SETUP_DOMAIN_CONTROLLER
;
1758 if (!secrets_init()) {
1759 libnet_join_set_error_string(mem_ctx
, r
,
1760 "Unable to open secrets database");
1761 return WERR_CAN_NOT_COMPLETE
;
1767 /****************************************************************
1768 ****************************************************************/
1770 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid
*domain_sid
)
1774 /* Try adding dom admins to builtin\admins. Only log failures. */
1775 status
= create_builtin_administrators(domain_sid
);
1776 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1777 DEBUG(10,("Unable to auto-add domain administrators to "
1778 "BUILTIN\\Administrators during join because "
1779 "winbindd must be running.\n"));
1780 } else if (!NT_STATUS_IS_OK(status
)) {
1781 DEBUG(5, ("Failed to auto-add domain administrators to "
1782 "BUILTIN\\Administrators during join: %s\n",
1783 nt_errstr(status
)));
1786 /* Try adding dom users to builtin\users. Only log failures. */
1787 status
= create_builtin_users(domain_sid
);
1788 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1789 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1790 "during join because winbindd must be running.\n"));
1791 } else if (!NT_STATUS_IS_OK(status
)) {
1792 DEBUG(5, ("Failed to auto-add domain administrators to "
1793 "BUILTIN\\Administrators during join: %s\n",
1794 nt_errstr(status
)));
1798 /****************************************************************
1799 ****************************************************************/
1801 static WERROR
libnet_join_post_processing(TALLOC_CTX
*mem_ctx
,
1802 struct libnet_JoinCtx
*r
)
1806 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1807 return r
->out
.result
;
1810 werr
= do_JoinConfig(r
);
1811 if (!W_ERROR_IS_OK(werr
)) {
1815 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1819 saf_join_store(r
->out
.netbios_domain_name
, r
->in
.dc_name
);
1820 if (r
->out
.dns_domain_name
) {
1821 saf_join_store(r
->out
.dns_domain_name
, r
->in
.dc_name
);
1825 if (r
->out
.domain_is_ad
&&
1826 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1827 ADS_STATUS ads_status
;
1829 ads_status
= libnet_join_post_processing_ads(mem_ctx
, r
);
1830 if (!ADS_ERR_OK(ads_status
)) {
1831 return WERR_GENERAL_FAILURE
;
1834 #endif /* HAVE_ADS */
1836 libnet_join_add_dom_rids_to_builtins(r
->out
.domain_sid
);
1841 /****************************************************************
1842 ****************************************************************/
1844 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx
*r
)
1847 ads_destroy(&r
->in
.ads
);
1853 /****************************************************************
1854 ****************************************************************/
1856 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx
*r
)
1859 ads_destroy(&r
->in
.ads
);
1865 /****************************************************************
1866 ****************************************************************/
1868 WERROR
libnet_init_JoinCtx(TALLOC_CTX
*mem_ctx
,
1869 struct libnet_JoinCtx
**r
)
1871 struct libnet_JoinCtx
*ctx
;
1873 ctx
= talloc_zero(mem_ctx
, struct libnet_JoinCtx
);
1878 talloc_set_destructor(ctx
, libnet_destroy_JoinCtx
);
1880 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, lp_netbios_name());
1881 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1883 ctx
->in
.secure_channel_type
= SEC_CHAN_WKSTA
;
1890 /****************************************************************
1891 ****************************************************************/
1893 WERROR
libnet_init_UnjoinCtx(TALLOC_CTX
*mem_ctx
,
1894 struct libnet_UnjoinCtx
**r
)
1896 struct libnet_UnjoinCtx
*ctx
;
1898 ctx
= talloc_zero(mem_ctx
, struct libnet_UnjoinCtx
);
1903 talloc_set_destructor(ctx
, libnet_destroy_UnjoinCtx
);
1905 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, lp_netbios_name());
1906 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1913 /****************************************************************
1914 ****************************************************************/
1916 static WERROR
libnet_join_check_config(TALLOC_CTX
*mem_ctx
,
1917 struct libnet_JoinCtx
*r
)
1919 bool valid_security
= false;
1920 bool valid_workgroup
= false;
1921 bool valid_realm
= false;
1923 /* check if configuration is already set correctly */
1925 valid_workgroup
= strequal(lp_workgroup(), r
->out
.netbios_domain_name
);
1927 switch (r
->out
.domain_is_ad
) {
1929 valid_security
= (lp_security() == SEC_DOMAIN
);
1930 if (valid_workgroup
&& valid_security
) {
1931 /* nothing to be done */
1936 valid_realm
= strequal(lp_realm(), r
->out
.dns_domain_name
);
1937 switch (lp_security()) {
1940 valid_security
= true;
1943 if (valid_workgroup
&& valid_realm
&& valid_security
) {
1944 /* nothing to be done */
1950 /* check if we are supposed to manipulate configuration */
1952 if (!r
->in
.modify_config
) {
1954 char *wrong_conf
= talloc_strdup(mem_ctx
, "");
1956 if (!valid_workgroup
) {
1957 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1958 "\"workgroup\" set to '%s', should be '%s'",
1959 lp_workgroup(), r
->out
.netbios_domain_name
);
1960 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1964 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1965 "\"realm\" set to '%s', should be '%s'",
1966 lp_realm(), r
->out
.dns_domain_name
);
1967 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1970 if (!valid_security
) {
1971 const char *sec
= NULL
;
1972 switch (lp_security()) {
1973 case SEC_USER
: sec
= "user"; break;
1974 case SEC_DOMAIN
: sec
= "domain"; break;
1975 case SEC_ADS
: sec
= "ads"; break;
1977 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1978 "\"security\" set to '%s', should be %s",
1979 sec
, r
->out
.domain_is_ad
?
1980 "either 'domain' or 'ads'" : "'domain'");
1981 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1984 libnet_join_set_error_string(mem_ctx
, r
,
1985 "Invalid configuration (%s) and configuration modification "
1986 "was not requested", wrong_conf
);
1987 return WERR_CAN_NOT_COMPLETE
;
1990 /* check if we are able to manipulate configuration */
1992 if (!lp_config_backend_is_registry()) {
1993 libnet_join_set_error_string(mem_ctx
, r
,
1994 "Configuration manipulation requested but not "
1995 "supported by backend");
1996 return WERR_NOT_SUPPORTED
;
2002 /****************************************************************
2003 ****************************************************************/
2005 static WERROR
libnet_DomainJoin(TALLOC_CTX
*mem_ctx
,
2006 struct libnet_JoinCtx
*r
)
2010 struct cli_state
*cli
= NULL
;
2012 ADS_STATUS ads_status
;
2013 #endif /* HAVE_ADS */
2015 if (!r
->in
.dc_name
) {
2016 struct netr_DsRGetDCNameInfo
*info
;
2018 status
= dsgetdcname(mem_ctx
,
2023 DS_FORCE_REDISCOVERY
|
2024 DS_DIRECTORY_SERVICE_REQUIRED
|
2025 DS_WRITABLE_REQUIRED
|
2028 if (!NT_STATUS_IS_OK(status
)) {
2029 libnet_join_set_error_string(mem_ctx
, r
,
2030 "failed to find DC for domain %s",
2032 get_friendly_nt_error_msg(status
));
2033 return WERR_DCNOTFOUND
;
2036 dc
= strip_hostname(info
->dc_unc
);
2037 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
2038 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
2041 status
= libnet_join_lookup_dc_rpc(mem_ctx
, r
, &cli
);
2042 if (!NT_STATUS_IS_OK(status
)) {
2043 libnet_join_set_error_string(mem_ctx
, r
,
2044 "failed to lookup DC info for domain '%s' over rpc: %s",
2045 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
2046 return ntstatus_to_werror(status
);
2049 werr
= libnet_join_check_config(mem_ctx
, r
);
2050 if (!W_ERROR_IS_OK(werr
)) {
2056 create_local_private_krb5_conf_for_domain(
2057 r
->out
.dns_domain_name
, r
->out
.netbios_domain_name
,
2058 NULL
, smbXcli_conn_remote_sockaddr(cli
->conn
),
2059 smbXcli_conn_remote_name(cli
->conn
));
2061 if (r
->out
.domain_is_ad
&& r
->in
.account_ou
&&
2062 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
2064 ads_status
= libnet_join_connect_ads(mem_ctx
, r
);
2065 if (!ADS_ERR_OK(ads_status
)) {
2066 return WERR_DEFAULT_JOIN_REQUIRED
;
2069 ads_status
= libnet_join_precreate_machine_acct(mem_ctx
, r
);
2070 if (!ADS_ERR_OK(ads_status
)) {
2071 libnet_join_set_error_string(mem_ctx
, r
,
2072 "failed to precreate account in ou %s: %s",
2074 ads_errstr(ads_status
));
2075 return WERR_DEFAULT_JOIN_REQUIRED
;
2078 r
->in
.join_flags
&= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
;
2080 #endif /* HAVE_ADS */
2082 if ((r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
) &&
2083 (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED
)) {
2084 status
= libnet_join_joindomain_rpc_unsecure(mem_ctx
, r
, cli
);
2086 status
= libnet_join_joindomain_rpc(mem_ctx
, r
, cli
);
2088 if (!NT_STATUS_IS_OK(status
)) {
2089 libnet_join_set_error_string(mem_ctx
, r
,
2090 "failed to join domain '%s' over rpc: %s",
2091 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
2092 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
2093 return WERR_SETUP_ALREADY_JOINED
;
2095 werr
= ntstatus_to_werror(status
);
2099 if (!libnet_join_joindomain_store_secrets(mem_ctx
, r
)) {
2100 werr
= WERR_SETUP_NOT_JOINED
;
2114 /****************************************************************
2115 ****************************************************************/
2117 static WERROR
libnet_join_rollback(TALLOC_CTX
*mem_ctx
,
2118 struct libnet_JoinCtx
*r
)
2121 struct libnet_UnjoinCtx
*u
= NULL
;
2123 werr
= libnet_init_UnjoinCtx(mem_ctx
, &u
);
2124 if (!W_ERROR_IS_OK(werr
)) {
2128 u
->in
.debug
= r
->in
.debug
;
2129 u
->in
.dc_name
= r
->in
.dc_name
;
2130 u
->in
.domain_name
= r
->in
.domain_name
;
2131 u
->in
.admin_account
= r
->in
.admin_account
;
2132 u
->in
.admin_password
= r
->in
.admin_password
;
2133 u
->in
.modify_config
= r
->in
.modify_config
;
2134 u
->in
.use_kerberos
= r
->in
.use_kerberos
;
2135 u
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
2136 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
2138 werr
= libnet_Unjoin(mem_ctx
, u
);
2144 /****************************************************************
2145 ****************************************************************/
2147 WERROR
libnet_Join(TALLOC_CTX
*mem_ctx
,
2148 struct libnet_JoinCtx
*r
)
2153 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx
, r
);
2156 ZERO_STRUCT(r
->out
);
2158 werr
= libnet_join_pre_processing(mem_ctx
, r
);
2159 if (!W_ERROR_IS_OK(werr
)) {
2163 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2164 werr
= libnet_DomainJoin(mem_ctx
, r
);
2165 if (!W_ERROR_IS_OK(werr
)) {
2170 werr
= libnet_join_post_processing(mem_ctx
, r
);
2171 if (!W_ERROR_IS_OK(werr
)) {
2175 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2176 werr
= libnet_join_post_verify(mem_ctx
, r
);
2177 if (!W_ERROR_IS_OK(werr
)) {
2178 libnet_join_rollback(mem_ctx
, r
);
2183 r
->out
.result
= werr
;
2186 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx
, r
);
2191 /****************************************************************
2192 ****************************************************************/
2194 static WERROR
libnet_DomainUnjoin(TALLOC_CTX
*mem_ctx
,
2195 struct libnet_UnjoinCtx
*r
)
2199 if (!r
->in
.domain_sid
) {
2201 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid
)) {
2202 libnet_unjoin_set_error_string(mem_ctx
, r
,
2203 "Unable to fetch domain sid: are we joined?");
2204 return WERR_SETUP_NOT_JOINED
;
2206 r
->in
.domain_sid
= dom_sid_dup(mem_ctx
, &sid
);
2207 W_ERROR_HAVE_NO_MEMORY(r
->in
.domain_sid
);
2210 if (!(r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) &&
2211 !r
->in
.delete_machine_account
) {
2212 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2216 if (!r
->in
.dc_name
) {
2217 struct netr_DsRGetDCNameInfo
*info
;
2219 status
= dsgetdcname(mem_ctx
,
2224 DS_DIRECTORY_SERVICE_REQUIRED
|
2225 DS_WRITABLE_REQUIRED
|
2228 if (!NT_STATUS_IS_OK(status
)) {
2229 libnet_unjoin_set_error_string(mem_ctx
, r
,
2230 "failed to find DC for domain %s",
2232 get_friendly_nt_error_msg(status
));
2233 return WERR_DCNOTFOUND
;
2236 dc
= strip_hostname(info
->dc_unc
);
2237 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
2238 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
2242 /* for net ads leave, try to delete the account. If it works,
2243 no sense in disabling. If it fails, we can still try to
2246 if (r
->in
.delete_machine_account
) {
2247 ADS_STATUS ads_status
;
2248 ads_status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
2249 if (ADS_ERR_OK(ads_status
)) {
2251 r
->out
.dns_domain_name
=
2252 talloc_strdup(mem_ctx
,
2253 r
->in
.ads
->server
.realm
);
2255 libnet_unjoin_remove_machine_acct(mem_ctx
, r
);
2257 if (!ADS_ERR_OK(ads_status
)) {
2258 libnet_unjoin_set_error_string(mem_ctx
, r
,
2259 "failed to remove machine account from AD: %s",
2260 ads_errstr(ads_status
));
2262 r
->out
.deleted_machine_account
= true;
2263 W_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
2264 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2268 #endif /* HAVE_ADS */
2270 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2272 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) {
2273 status
= libnet_join_unjoindomain_rpc(mem_ctx
, r
);
2274 if (!NT_STATUS_IS_OK(status
)) {
2275 libnet_unjoin_set_error_string(mem_ctx
, r
,
2276 "failed to disable machine account via rpc: %s",
2277 get_friendly_nt_error_msg(status
));
2278 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
2279 return WERR_SETUP_NOT_JOINED
;
2281 return ntstatus_to_werror(status
);
2284 r
->out
.disabled_machine_account
= true;
2287 /* If disable succeeded or was not requested at all, we
2288 should be getting rid of our end of things */
2290 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2295 /****************************************************************
2296 ****************************************************************/
2298 static WERROR
libnet_unjoin_pre_processing(TALLOC_CTX
*mem_ctx
,
2299 struct libnet_UnjoinCtx
*r
)
2301 if (!r
->in
.domain_name
) {
2302 libnet_unjoin_set_error_string(mem_ctx
, r
,
2303 "No domain name defined");
2304 return WERR_INVALID_PARAM
;
2307 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
2310 libnet_unjoin_set_error_string(mem_ctx
, r
,
2311 "Failed to parse domain name");
2312 return WERR_INVALID_PARAM
;
2316 return WERR_SETUP_DOMAIN_CONTROLLER
;
2319 if (!secrets_init()) {
2320 libnet_unjoin_set_error_string(mem_ctx
, r
,
2321 "Unable to open secrets database");
2322 return WERR_CAN_NOT_COMPLETE
;
2328 /****************************************************************
2329 ****************************************************************/
2331 static WERROR
libnet_unjoin_post_processing(TALLOC_CTX
*mem_ctx
,
2332 struct libnet_UnjoinCtx
*r
)
2334 saf_delete(r
->out
.netbios_domain_name
);
2335 saf_delete(r
->out
.dns_domain_name
);
2337 return libnet_unjoin_config(r
);
2340 /****************************************************************
2341 ****************************************************************/
2343 WERROR
libnet_Unjoin(TALLOC_CTX
*mem_ctx
,
2344 struct libnet_UnjoinCtx
*r
)
2349 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx
, r
);
2352 werr
= libnet_unjoin_pre_processing(mem_ctx
, r
);
2353 if (!W_ERROR_IS_OK(werr
)) {
2357 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2358 werr
= libnet_DomainUnjoin(mem_ctx
, r
);
2359 if (!W_ERROR_IS_OK(werr
)) {
2360 libnet_unjoin_config(r
);
2365 werr
= libnet_unjoin_post_processing(mem_ctx
, r
);
2366 if (!W_ERROR_IS_OK(werr
)) {
2371 r
->out
.result
= werr
;
2374 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx
, r
);