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 static ADS_STATUS
libnet_join_get_machine_spns(TALLOC_CTX
*mem_ctx
,
362 struct libnet_JoinCtx
*r
,
368 if (r
->in
.machine_name
== NULL
) {
369 return ADS_ERROR_SYSTEM(EINVAL
);
372 status
= ads_get_service_principal_names(mem_ctx
,
381 /****************************************************************
382 Set a machines dNSHostName and servicePrincipalName attributes
383 ****************************************************************/
385 static ADS_STATUS
libnet_join_set_machine_spn(TALLOC_CTX
*mem_ctx
,
386 struct libnet_JoinCtx
*r
)
391 const char **spn_array
= NULL
;
398 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
399 if (!ADS_ERR_OK(status
)) {
403 status
= libnet_join_get_machine_spns(mem_ctx
,
405 discard_const_p(char **, &spn_array
),
407 if (!ADS_ERR_OK(status
)) {
408 DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
411 /* Windows only creates HOST/shortname & HOST/fqdn. */
413 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", r
->in
.machine_name
);
415 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
417 if (!strupper_m(spn
)) {
418 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
421 ok
= ads_element_in_array(spn_array
, num_spns
, spn
);
423 ok
= add_string_to_array(spn_array
, spn
,
424 &spn_array
, &num_spns
);
426 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
430 if (!name_to_fqdn(my_fqdn
, r
->in
.machine_name
)
431 || (strchr(my_fqdn
, '.') == NULL
)) {
432 fstr_sprintf(my_fqdn
, "%s.%s", r
->in
.machine_name
,
433 r
->out
.dns_domain_name
);
436 if (!strlower_m(my_fqdn
)) {
437 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
440 if (!strequal(my_fqdn
, r
->in
.machine_name
)) {
441 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", my_fqdn
);
443 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
446 ok
= ads_element_in_array(spn_array
, num_spns
, spn
);
448 ok
= add_string_to_array(spn_array
, spn
,
449 &spn_array
, &num_spns
);
451 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
456 /* make sure to NULL terminate the array */
457 spn_array
= talloc_realloc(mem_ctx
, spn_array
, const char *, num_spns
+ 1);
458 if (spn_array
== NULL
) {
459 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
461 spn_array
[num_spns
] = NULL
;
463 mods
= ads_init_mods(mem_ctx
);
465 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
468 /* fields of primary importance */
470 status
= ads_mod_str(mem_ctx
, &mods
, "dNSHostName", my_fqdn
);
471 if (!ADS_ERR_OK(status
)) {
472 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
475 status
= ads_mod_strlist(mem_ctx
, &mods
, "servicePrincipalName",
477 if (!ADS_ERR_OK(status
)) {
478 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
481 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
484 /****************************************************************
485 ****************************************************************/
487 static ADS_STATUS
libnet_join_set_machine_upn(TALLOC_CTX
*mem_ctx
,
488 struct libnet_JoinCtx
*r
)
493 if (!r
->in
.create_upn
) {
499 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
500 if (!ADS_ERR_OK(status
)) {
505 const char *realm
= r
->out
.dns_domain_name
;
507 /* in case we are about to generate a keytab during the join
508 * make sure the default upn we create is usable with kinit -k.
511 if (USE_KERBEROS_KEYTAB
) {
512 realm
= talloc_strdup_upper(mem_ctx
,
513 r
->out
.dns_domain_name
);
517 return ADS_ERROR(LDAP_NO_MEMORY
);
520 r
->in
.upn
= talloc_asprintf(mem_ctx
,
525 return ADS_ERROR(LDAP_NO_MEMORY
);
529 /* now do the mods */
531 mods
= ads_init_mods(mem_ctx
);
533 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
536 /* fields of primary importance */
538 status
= ads_mod_str(mem_ctx
, &mods
, "userPrincipalName", r
->in
.upn
);
539 if (!ADS_ERR_OK(status
)) {
540 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
543 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
547 /****************************************************************
548 ****************************************************************/
550 static ADS_STATUS
libnet_join_set_os_attributes(TALLOC_CTX
*mem_ctx
,
551 struct libnet_JoinCtx
*r
)
557 if (!r
->in
.os_name
|| !r
->in
.os_version
) {
563 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
564 if (!ADS_ERR_OK(status
)) {
568 /* now do the mods */
570 mods
= ads_init_mods(mem_ctx
);
572 return ADS_ERROR(LDAP_NO_MEMORY
);
575 os_sp
= talloc_asprintf(mem_ctx
, "Samba %s", samba_version_string());
577 return ADS_ERROR(LDAP_NO_MEMORY
);
580 /* fields of primary importance */
582 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystem",
584 if (!ADS_ERR_OK(status
)) {
588 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemVersion",
590 if (!ADS_ERR_OK(status
)) {
594 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemServicePack",
596 if (!ADS_ERR_OK(status
)) {
600 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
603 /****************************************************************
604 ****************************************************************/
606 static bool libnet_join_create_keytab(TALLOC_CTX
*mem_ctx
,
607 struct libnet_JoinCtx
*r
)
609 if (!USE_SYSTEM_KEYTAB
) {
613 if (ads_keytab_create_default(r
->in
.ads
) != 0) {
620 /****************************************************************
621 ****************************************************************/
623 static bool libnet_join_derive_salting_principal(TALLOC_CTX
*mem_ctx
,
624 struct libnet_JoinCtx
*r
)
626 uint32_t domain_func
;
628 const char *salt
= NULL
;
629 char *std_salt
= NULL
;
631 status
= ads_domain_func_level(r
->in
.ads
, &domain_func
);
632 if (!ADS_ERR_OK(status
)) {
633 libnet_join_set_error_string(mem_ctx
, r
,
634 "failed to determine domain functional level: %s",
639 /* go ahead and setup the default salt */
641 std_salt
= kerberos_standard_des_salt();
643 libnet_join_set_error_string(mem_ctx
, r
,
644 "failed to obtain standard DES salt");
648 salt
= talloc_strdup(mem_ctx
, std_salt
);
655 /* if it's a Windows functional domain, we have to look for the UPN */
657 if (domain_func
== DS_DOMAIN_FUNCTION_2000
) {
660 upn
= ads_get_upn(r
->in
.ads
, mem_ctx
,
663 salt
= talloc_strdup(mem_ctx
, upn
);
670 return kerberos_secrets_store_des_salt(salt
);
673 /****************************************************************
674 ****************************************************************/
676 static ADS_STATUS
libnet_join_post_processing_ads(TALLOC_CTX
*mem_ctx
,
677 struct libnet_JoinCtx
*r
)
682 status
= libnet_join_connect_ads(mem_ctx
, r
);
683 if (!ADS_ERR_OK(status
)) {
688 status
= libnet_join_set_machine_spn(mem_ctx
, r
);
689 if (!ADS_ERR_OK(status
)) {
690 libnet_join_set_error_string(mem_ctx
, r
,
691 "failed to set machine spn: %s",
696 status
= libnet_join_set_os_attributes(mem_ctx
, r
);
697 if (!ADS_ERR_OK(status
)) {
698 libnet_join_set_error_string(mem_ctx
, r
,
699 "failed to set machine os attributes: %s",
704 status
= libnet_join_set_machine_upn(mem_ctx
, r
);
705 if (!ADS_ERR_OK(status
)) {
706 libnet_join_set_error_string(mem_ctx
, r
,
707 "failed to set machine upn: %s",
712 if (!libnet_join_derive_salting_principal(mem_ctx
, r
)) {
713 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
716 if (!libnet_join_create_keytab(mem_ctx
, r
)) {
717 libnet_join_set_error_string(mem_ctx
, r
,
718 "failed to create kerberos keytab");
719 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
724 #endif /* HAVE_ADS */
726 /****************************************************************
727 Store the machine password and domain SID
728 ****************************************************************/
730 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX
*mem_ctx
,
731 struct libnet_JoinCtx
*r
)
733 if (!secrets_store_domain_sid(r
->out
.netbios_domain_name
,
736 DEBUG(1,("Failed to save domain sid\n"));
740 if (!secrets_store_machine_password(r
->in
.machine_password
,
741 r
->out
.netbios_domain_name
,
742 r
->in
.secure_channel_type
))
744 DEBUG(1,("Failed to save machine password\n"));
751 /****************************************************************
752 Connect dc's IPC$ share
753 ****************************************************************/
755 static NTSTATUS
libnet_join_connect_dc_ipc(const char *dc
,
759 struct cli_state
**cli
)
764 flags
|= CLI_FULL_CONNECTION_USE_KERBEROS
;
767 if (use_kerberos
&& pass
) {
768 flags
|= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS
;
771 return cli_full_connection(cli
, NULL
,
779 SMB_SIGNING_DEFAULT
);
782 /****************************************************************
783 Lookup domain dc's info
784 ****************************************************************/
786 static NTSTATUS
libnet_join_lookup_dc_rpc(TALLOC_CTX
*mem_ctx
,
787 struct libnet_JoinCtx
*r
,
788 struct cli_state
**cli
)
790 struct rpc_pipe_client
*pipe_hnd
= NULL
;
791 struct policy_handle lsa_pol
;
792 NTSTATUS status
, result
;
793 union lsa_PolicyInformation
*info
= NULL
;
794 struct dcerpc_binding_handle
*b
;
796 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
798 r
->in
.admin_password
,
801 if (!NT_STATUS_IS_OK(status
)) {
805 status
= cli_rpc_pipe_open_noauth(*cli
, &ndr_table_lsarpc
.syntax_id
,
807 if (!NT_STATUS_IS_OK(status
)) {
808 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
813 b
= pipe_hnd
->binding_handle
;
815 status
= rpccli_lsa_open_policy(pipe_hnd
, mem_ctx
, true,
816 SEC_FLAG_MAXIMUM_ALLOWED
, &lsa_pol
);
817 if (!NT_STATUS_IS_OK(status
)) {
821 status
= dcerpc_lsa_QueryInfoPolicy2(b
, mem_ctx
,
826 if (NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(result
)) {
827 r
->out
.domain_is_ad
= true;
828 r
->out
.netbios_domain_name
= info
->dns
.name
.string
;
829 r
->out
.dns_domain_name
= info
->dns
.dns_domain
.string
;
830 r
->out
.forest_name
= info
->dns
.dns_forest
.string
;
831 r
->out
.domain_sid
= dom_sid_dup(mem_ctx
, info
->dns
.sid
);
832 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
835 if (!NT_STATUS_IS_OK(status
)) {
836 status
= dcerpc_lsa_QueryInfoPolicy(b
, mem_ctx
,
838 LSA_POLICY_INFO_ACCOUNT_DOMAIN
,
841 if (!NT_STATUS_IS_OK(status
)) {
844 if (!NT_STATUS_IS_OK(result
)) {
849 r
->out
.netbios_domain_name
= info
->account_domain
.name
.string
;
850 r
->out
.domain_sid
= dom_sid_dup(mem_ctx
, info
->account_domain
.sid
);
851 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
854 dcerpc_lsa_Close(b
, mem_ctx
, &lsa_pol
, &result
);
855 TALLOC_FREE(pipe_hnd
);
861 /****************************************************************
862 Do the domain join unsecure
863 ****************************************************************/
865 static NTSTATUS
libnet_join_joindomain_rpc_unsecure(TALLOC_CTX
*mem_ctx
,
866 struct libnet_JoinCtx
*r
,
867 struct cli_state
*cli
)
869 struct rpc_pipe_client
*pipe_hnd
= NULL
;
870 unsigned char orig_trust_passwd_hash
[16];
871 unsigned char new_trust_passwd_hash
[16];
872 fstring trust_passwd
;
875 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_netlogon
.syntax_id
,
877 if (!NT_STATUS_IS_OK(status
)) {
881 if (!r
->in
.machine_password
) {
882 r
->in
.machine_password
= generate_random_password(mem_ctx
,
883 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
,
884 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
885 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
888 E_md4hash(r
->in
.machine_password
, new_trust_passwd_hash
);
890 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
891 fstrcpy(trust_passwd
, r
->in
.admin_password
);
892 if (!strlower_m(trust_passwd
)) {
893 return NT_STATUS_INVALID_PARAMETER
;
897 * Machine names can be 15 characters, but the max length on
898 * a password is 14. --jerry
901 trust_passwd
[14] = '\0';
903 E_md4hash(trust_passwd
, orig_trust_passwd_hash
);
905 status
= rpccli_netlogon_set_trust_password(pipe_hnd
, mem_ctx
,
907 orig_trust_passwd_hash
,
908 r
->in
.machine_password
,
909 new_trust_passwd_hash
,
910 r
->in
.secure_channel_type
);
915 /****************************************************************
917 ****************************************************************/
919 static NTSTATUS
libnet_join_joindomain_rpc(TALLOC_CTX
*mem_ctx
,
920 struct libnet_JoinCtx
*r
,
921 struct cli_state
*cli
)
923 struct rpc_pipe_client
*pipe_hnd
= NULL
;
924 struct policy_handle sam_pol
, domain_pol
, user_pol
;
925 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
, result
;
927 struct lsa_String lsa_acct_name
;
929 uint32_t acct_flags
= ACB_WSTRUST
;
930 struct samr_Ids user_rids
;
931 struct samr_Ids name_types
;
932 union samr_UserInfo user_info
;
933 struct dcerpc_binding_handle
*b
= NULL
;
934 unsigned int old_timeout
= 0;
936 DATA_BLOB session_key
= data_blob_null
;
937 struct samr_CryptPassword crypt_pwd
;
938 struct samr_CryptPasswordEx crypt_pwd_ex
;
940 ZERO_STRUCT(sam_pol
);
941 ZERO_STRUCT(domain_pol
);
942 ZERO_STRUCT(user_pol
);
944 switch (r
->in
.secure_channel_type
) {
946 acct_flags
= ACB_WSTRUST
;
949 acct_flags
= ACB_SVRTRUST
;
952 return NT_STATUS_INVALID_PARAMETER
;
955 if (!r
->in
.machine_password
) {
956 r
->in
.machine_password
= generate_random_password(mem_ctx
,
957 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
,
958 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
959 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
962 /* Open the domain */
964 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
966 if (!NT_STATUS_IS_OK(status
)) {
967 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
972 b
= pipe_hnd
->binding_handle
;
974 status
= cli_get_session_key(mem_ctx
, pipe_hnd
, &session_key
);
975 if (!NT_STATUS_IS_OK(status
)) {
976 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
981 status
= dcerpc_samr_Connect2(b
, mem_ctx
,
983 SAMR_ACCESS_ENUM_DOMAINS
984 | SAMR_ACCESS_LOOKUP_DOMAIN
,
987 if (!NT_STATUS_IS_OK(status
)) {
990 if (!NT_STATUS_IS_OK(result
)) {
995 status
= dcerpc_samr_OpenDomain(b
, mem_ctx
,
997 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
998 | SAMR_DOMAIN_ACCESS_CREATE_USER
999 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT
,
1003 if (!NT_STATUS_IS_OK(status
)) {
1006 if (!NT_STATUS_IS_OK(result
)) {
1011 /* Create domain user */
1013 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
1014 if (!strlower_m(acct_name
)) {
1015 status
= NT_STATUS_INVALID_PARAMETER
;
1019 init_lsa_String(&lsa_acct_name
, acct_name
);
1021 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
) {
1022 uint32_t access_desired
=
1023 SEC_GENERIC_READ
| SEC_GENERIC_WRITE
| SEC_GENERIC_EXECUTE
|
1024 SEC_STD_WRITE_DAC
| SEC_STD_DELETE
|
1025 SAMR_USER_ACCESS_SET_PASSWORD
|
1026 SAMR_USER_ACCESS_GET_ATTRIBUTES
|
1027 SAMR_USER_ACCESS_SET_ATTRIBUTES
;
1028 uint32_t access_granted
= 0;
1030 DEBUG(10,("Creating account with desired access mask: %d\n",
1033 status
= dcerpc_samr_CreateUser2(b
, mem_ctx
,
1042 if (!NT_STATUS_IS_OK(status
)) {
1047 if (!NT_STATUS_IS_OK(status
) &&
1048 !NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
1050 DEBUG(10,("Creation of workstation account failed: %s\n",
1051 nt_errstr(status
)));
1053 /* If NT_STATUS_ACCESS_DENIED then we have a valid
1054 username/password combo but the user does not have
1055 administrator access. */
1057 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1058 libnet_join_set_error_string(mem_ctx
, r
,
1059 "User specified does not have "
1060 "administrator privileges");
1066 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
1067 if (!(r
->in
.join_flags
&
1068 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
)) {
1073 /* We *must* do this.... don't ask... */
1075 if (NT_STATUS_IS_OK(status
)) {
1076 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1080 status
= dcerpc_samr_LookupNames(b
, mem_ctx
,
1087 if (!NT_STATUS_IS_OK(status
)) {
1090 if (!NT_STATUS_IS_OK(result
)) {
1094 if (user_rids
.count
!= 1) {
1095 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1098 if (name_types
.count
!= 1) {
1099 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1103 if (name_types
.ids
[0] != SID_NAME_USER
) {
1104 DEBUG(0,("%s is not a user account (type=%d)\n",
1105 acct_name
, name_types
.ids
[0]));
1106 status
= NT_STATUS_INVALID_WORKSTATION
;
1110 user_rid
= user_rids
.ids
[0];
1112 /* Open handle on user */
1114 status
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1116 SEC_FLAG_MAXIMUM_ALLOWED
,
1120 if (!NT_STATUS_IS_OK(status
)) {
1123 if (!NT_STATUS_IS_OK(result
)) {
1128 /* Fill in the additional account flags now */
1130 acct_flags
|= ACB_PWNOEXP
;
1132 /* Set account flags on machine account */
1133 ZERO_STRUCT(user_info
.info16
);
1134 user_info
.info16
.acct_flags
= acct_flags
;
1136 status
= dcerpc_samr_SetUserInfo(b
, mem_ctx
,
1141 if (!NT_STATUS_IS_OK(status
)) {
1142 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1146 libnet_join_set_error_string(mem_ctx
, r
,
1147 "Failed to set account flags for machine account (%s)\n",
1152 if (!NT_STATUS_IS_OK(result
)) {
1155 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1159 libnet_join_set_error_string(mem_ctx
, r
,
1160 "Failed to set account flags for machine account (%s)\n",
1165 /* Set password on machine account - first try level 26 */
1168 * increase the timeout as password filter modules on the DC
1169 * might delay the operation for a significant amount of time
1171 old_timeout
= rpccli_set_timeout(pipe_hnd
, 600000);
1173 init_samr_CryptPasswordEx(r
->in
.machine_password
,
1177 user_info
.info26
.password
= crypt_pwd_ex
;
1178 user_info
.info26
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1180 status
= dcerpc_samr_SetUserInfo2(b
, mem_ctx
,
1186 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
)) {
1188 /* retry with level 24 */
1190 init_samr_CryptPassword(r
->in
.machine_password
,
1194 user_info
.info24
.password
= crypt_pwd
;
1195 user_info
.info24
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1197 status
= dcerpc_samr_SetUserInfo2(b
, mem_ctx
,
1204 old_timeout
= rpccli_set_timeout(pipe_hnd
, old_timeout
);
1206 if (!NT_STATUS_IS_OK(status
)) {
1208 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1212 libnet_join_set_error_string(mem_ctx
, r
,
1213 "Failed to set password for machine account (%s)\n",
1217 if (!NT_STATUS_IS_OK(result
)) {
1220 dcerpc_samr_DeleteUser(b
, mem_ctx
,
1224 libnet_join_set_error_string(mem_ctx
, r
,
1225 "Failed to set password for machine account (%s)\n",
1230 status
= NT_STATUS_OK
;
1237 data_blob_clear_free(&session_key
);
1239 if (is_valid_policy_hnd(&sam_pol
)) {
1240 dcerpc_samr_Close(b
, mem_ctx
, &sam_pol
, &result
);
1242 if (is_valid_policy_hnd(&domain_pol
)) {
1243 dcerpc_samr_Close(b
, mem_ctx
, &domain_pol
, &result
);
1245 if (is_valid_policy_hnd(&user_pol
)) {
1246 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1248 TALLOC_FREE(pipe_hnd
);
1253 /****************************************************************
1254 ****************************************************************/
1256 NTSTATUS
libnet_join_ok(const char *netbios_domain_name
,
1257 const char *machine_name
,
1258 const char *dc_name
,
1259 const bool use_kerberos
)
1261 uint32_t neg_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
1262 struct cli_state
*cli
= NULL
;
1263 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1264 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1266 char *machine_password
= NULL
;
1267 char *machine_account
= NULL
;
1271 return NT_STATUS_INVALID_PARAMETER
;
1274 if (!secrets_init()) {
1275 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1278 machine_password
= secrets_fetch_machine_password(netbios_domain_name
,
1280 if (!machine_password
) {
1281 return NT_STATUS_NO_TRUST_LSA_SECRET
;
1284 if (asprintf(&machine_account
, "%s$", machine_name
) == -1) {
1285 SAFE_FREE(machine_password
);
1286 return NT_STATUS_NO_MEMORY
;
1290 flags
|= CLI_FULL_CONNECTION_USE_KERBEROS
;
1293 status
= cli_full_connection(&cli
, NULL
,
1301 SMB_SIGNING_DEFAULT
);
1302 free(machine_account
);
1303 free(machine_password
);
1305 if (!NT_STATUS_IS_OK(status
)) {
1306 status
= cli_full_connection(&cli
, NULL
,
1314 SMB_SIGNING_DEFAULT
);
1317 if (!NT_STATUS_IS_OK(status
)) {
1321 status
= get_schannel_session_key(cli
, netbios_domain_name
,
1322 &neg_flags
, &netlogon_pipe
);
1323 if (!NT_STATUS_IS_OK(status
)) {
1324 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_NETWORK_RESPONSE
)) {
1326 return NT_STATUS_OK
;
1329 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1330 "key from server %s for domain %s. Error was %s\n",
1331 smbXcli_conn_remote_name(cli
->conn
),
1332 netbios_domain_name
, nt_errstr(status
)));
1337 if (!lp_client_schannel()) {
1339 return NT_STATUS_OK
;
1342 status
= cli_rpc_pipe_open_schannel_with_key(
1343 cli
, &ndr_table_netlogon
.syntax_id
, NCACN_NP
,
1344 DCERPC_AUTH_LEVEL_PRIVACY
,
1345 netbios_domain_name
, &netlogon_pipe
->dc
, &pipe_hnd
);
1349 if (!NT_STATUS_IS_OK(status
)) {
1350 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1351 "on netlogon pipe to server %s for domain %s. "
1353 smbXcli_conn_remote_name(cli
->conn
),
1354 netbios_domain_name
, nt_errstr(status
)));
1358 return NT_STATUS_OK
;
1361 /****************************************************************
1362 ****************************************************************/
1364 static WERROR
libnet_join_post_verify(TALLOC_CTX
*mem_ctx
,
1365 struct libnet_JoinCtx
*r
)
1369 status
= libnet_join_ok(r
->out
.netbios_domain_name
,
1372 r
->in
.use_kerberos
);
1373 if (!NT_STATUS_IS_OK(status
)) {
1374 libnet_join_set_error_string(mem_ctx
, r
,
1375 "failed to verify domain membership after joining: %s",
1376 get_friendly_nt_error_msg(status
));
1377 return WERR_SETUP_NOT_JOINED
;
1383 /****************************************************************
1384 ****************************************************************/
1386 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX
*mem_ctx
,
1387 struct libnet_UnjoinCtx
*r
)
1389 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1393 if (!secrets_delete_domain_sid(lp_workgroup())) {
1400 /****************************************************************
1401 ****************************************************************/
1403 static NTSTATUS
libnet_join_unjoindomain_rpc(TALLOC_CTX
*mem_ctx
,
1404 struct libnet_UnjoinCtx
*r
)
1406 struct cli_state
*cli
= NULL
;
1407 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1408 struct policy_handle sam_pol
, domain_pol
, user_pol
;
1409 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
, result
;
1412 struct lsa_String lsa_acct_name
;
1413 struct samr_Ids user_rids
;
1414 struct samr_Ids name_types
;
1415 union samr_UserInfo
*info
= NULL
;
1416 struct dcerpc_binding_handle
*b
= NULL
;
1418 ZERO_STRUCT(sam_pol
);
1419 ZERO_STRUCT(domain_pol
);
1420 ZERO_STRUCT(user_pol
);
1422 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
1423 r
->in
.admin_account
,
1424 r
->in
.admin_password
,
1427 if (!NT_STATUS_IS_OK(status
)) {
1431 /* Open the domain */
1433 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
1435 if (!NT_STATUS_IS_OK(status
)) {
1436 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1437 nt_errstr(status
)));
1441 b
= pipe_hnd
->binding_handle
;
1443 status
= dcerpc_samr_Connect2(b
, mem_ctx
,
1445 SEC_FLAG_MAXIMUM_ALLOWED
,
1448 if (!NT_STATUS_IS_OK(status
)) {
1451 if (!NT_STATUS_IS_OK(result
)) {
1456 status
= dcerpc_samr_OpenDomain(b
, mem_ctx
,
1458 SEC_FLAG_MAXIMUM_ALLOWED
,
1462 if (!NT_STATUS_IS_OK(status
)) {
1465 if (!NT_STATUS_IS_OK(result
)) {
1470 /* Create domain user */
1472 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
1473 if (!strlower_m(acct_name
)) {
1474 status
= NT_STATUS_INVALID_PARAMETER
;
1478 init_lsa_String(&lsa_acct_name
, acct_name
);
1480 status
= dcerpc_samr_LookupNames(b
, mem_ctx
,
1488 if (!NT_STATUS_IS_OK(status
)) {
1491 if (!NT_STATUS_IS_OK(result
)) {
1495 if (user_rids
.count
!= 1) {
1496 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1499 if (name_types
.count
!= 1) {
1500 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1504 if (name_types
.ids
[0] != SID_NAME_USER
) {
1505 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name
,
1506 name_types
.ids
[0]));
1507 status
= NT_STATUS_INVALID_WORKSTATION
;
1511 user_rid
= user_rids
.ids
[0];
1513 /* Open handle on user */
1515 status
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1517 SEC_FLAG_MAXIMUM_ALLOWED
,
1521 if (!NT_STATUS_IS_OK(status
)) {
1524 if (!NT_STATUS_IS_OK(result
)) {
1531 status
= dcerpc_samr_QueryUserInfo(b
, mem_ctx
,
1536 if (!NT_STATUS_IS_OK(status
)) {
1537 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1540 if (!NT_STATUS_IS_OK(result
)) {
1542 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1546 /* now disable and setuser info */
1548 info
->info16
.acct_flags
|= ACB_DISABLED
;
1550 status
= dcerpc_samr_SetUserInfo(b
, mem_ctx
,
1555 if (!NT_STATUS_IS_OK(status
)) {
1556 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1559 if (!NT_STATUS_IS_OK(result
)) {
1561 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1565 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result
);
1568 if (pipe_hnd
&& b
) {
1569 if (is_valid_policy_hnd(&domain_pol
)) {
1570 dcerpc_samr_Close(b
, mem_ctx
, &domain_pol
, &result
);
1572 if (is_valid_policy_hnd(&sam_pol
)) {
1573 dcerpc_samr_Close(b
, mem_ctx
, &sam_pol
, &result
);
1575 TALLOC_FREE(pipe_hnd
);
1585 /****************************************************************
1586 ****************************************************************/
1588 static WERROR
do_join_modify_vals_config(struct libnet_JoinCtx
*r
)
1590 WERROR werr
= WERR_OK
;
1592 struct smbconf_ctx
*ctx
;
1594 err
= smbconf_init_reg(r
, &ctx
, NULL
);
1595 if (!SBC_ERROR_IS_OK(err
)) {
1596 werr
= WERR_NO_SUCH_SERVICE
;
1600 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1602 err
= smbconf_set_global_parameter(ctx
, "security", "user");
1603 if (!SBC_ERROR_IS_OK(err
)) {
1604 werr
= WERR_NO_SUCH_SERVICE
;
1608 err
= smbconf_set_global_parameter(ctx
, "workgroup",
1610 if (!SBC_ERROR_IS_OK(err
)) {
1611 werr
= WERR_NO_SUCH_SERVICE
;
1615 smbconf_delete_global_parameter(ctx
, "realm");
1619 err
= smbconf_set_global_parameter(ctx
, "security", "domain");
1620 if (!SBC_ERROR_IS_OK(err
)) {
1621 werr
= WERR_NO_SUCH_SERVICE
;
1625 err
= smbconf_set_global_parameter(ctx
, "workgroup",
1626 r
->out
.netbios_domain_name
);
1627 if (!SBC_ERROR_IS_OK(err
)) {
1628 werr
= WERR_NO_SUCH_SERVICE
;
1632 if (r
->out
.domain_is_ad
) {
1633 err
= smbconf_set_global_parameter(ctx
, "security", "ads");
1634 if (!SBC_ERROR_IS_OK(err
)) {
1635 werr
= WERR_NO_SUCH_SERVICE
;
1639 err
= smbconf_set_global_parameter(ctx
, "realm",
1640 r
->out
.dns_domain_name
);
1641 if (!SBC_ERROR_IS_OK(err
)) {
1642 werr
= WERR_NO_SUCH_SERVICE
;
1648 smbconf_shutdown(ctx
);
1652 /****************************************************************
1653 ****************************************************************/
1655 static WERROR
do_unjoin_modify_vals_config(struct libnet_UnjoinCtx
*r
)
1657 WERROR werr
= WERR_OK
;
1659 struct smbconf_ctx
*ctx
;
1661 err
= smbconf_init_reg(r
, &ctx
, NULL
);
1662 if (!SBC_ERROR_IS_OK(err
)) {
1663 werr
= WERR_NO_SUCH_SERVICE
;
1667 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1669 err
= smbconf_set_global_parameter(ctx
, "security", "user");
1670 if (!SBC_ERROR_IS_OK(err
)) {
1671 werr
= WERR_NO_SUCH_SERVICE
;
1675 err
= smbconf_delete_global_parameter(ctx
, "workgroup");
1676 if (!SBC_ERROR_IS_OK(err
)) {
1677 werr
= WERR_NO_SUCH_SERVICE
;
1681 smbconf_delete_global_parameter(ctx
, "realm");
1685 smbconf_shutdown(ctx
);
1689 /****************************************************************
1690 ****************************************************************/
1692 static WERROR
do_JoinConfig(struct libnet_JoinCtx
*r
)
1696 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1697 return r
->out
.result
;
1700 if (!r
->in
.modify_config
) {
1704 werr
= do_join_modify_vals_config(r
);
1705 if (!W_ERROR_IS_OK(werr
)) {
1709 lp_load_global(get_dyn_CONFIGFILE());
1711 r
->out
.modified_config
= true;
1712 r
->out
.result
= werr
;
1717 /****************************************************************
1718 ****************************************************************/
1720 static WERROR
libnet_unjoin_config(struct libnet_UnjoinCtx
*r
)
1724 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1725 return r
->out
.result
;
1728 if (!r
->in
.modify_config
) {
1732 werr
= do_unjoin_modify_vals_config(r
);
1733 if (!W_ERROR_IS_OK(werr
)) {
1737 lp_load_global(get_dyn_CONFIGFILE());
1739 r
->out
.modified_config
= true;
1740 r
->out
.result
= werr
;
1745 /****************************************************************
1746 ****************************************************************/
1748 static bool libnet_parse_domain_dc(TALLOC_CTX
*mem_ctx
,
1749 const char *domain_str
,
1750 const char **domain_p
,
1753 char *domain
= NULL
;
1755 const char *p
= NULL
;
1757 if (!domain_str
|| !domain_p
|| !dc_p
) {
1761 p
= strchr_m(domain_str
, '\\');
1764 domain
= talloc_strndup(mem_ctx
, domain_str
,
1765 PTR_DIFF(p
, domain_str
));
1766 dc
= talloc_strdup(mem_ctx
, p
+1);
1771 domain
= talloc_strdup(mem_ctx
, domain_str
);
1787 /****************************************************************
1788 ****************************************************************/
1790 static WERROR
libnet_join_pre_processing(TALLOC_CTX
*mem_ctx
,
1791 struct libnet_JoinCtx
*r
)
1793 if (!r
->in
.domain_name
) {
1794 libnet_join_set_error_string(mem_ctx
, r
,
1795 "No domain name defined");
1796 return WERR_INVALID_PARAM
;
1799 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
1802 libnet_join_set_error_string(mem_ctx
, r
,
1803 "Failed to parse domain name");
1804 return WERR_INVALID_PARAM
;
1808 return WERR_SETUP_DOMAIN_CONTROLLER
;
1811 if (!secrets_init()) {
1812 libnet_join_set_error_string(mem_ctx
, r
,
1813 "Unable to open secrets database");
1814 return WERR_CAN_NOT_COMPLETE
;
1820 /****************************************************************
1821 ****************************************************************/
1823 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid
*domain_sid
)
1827 /* Try adding dom admins to builtin\admins. Only log failures. */
1828 status
= create_builtin_administrators(domain_sid
);
1829 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1830 DEBUG(10,("Unable to auto-add domain administrators to "
1831 "BUILTIN\\Administrators during join because "
1832 "winbindd must be running.\n"));
1833 } else if (!NT_STATUS_IS_OK(status
)) {
1834 DEBUG(5, ("Failed to auto-add domain administrators to "
1835 "BUILTIN\\Administrators during join: %s\n",
1836 nt_errstr(status
)));
1839 /* Try adding dom users to builtin\users. Only log failures. */
1840 status
= create_builtin_users(domain_sid
);
1841 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1842 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1843 "during join because winbindd must be running.\n"));
1844 } else if (!NT_STATUS_IS_OK(status
)) {
1845 DEBUG(5, ("Failed to auto-add domain administrators to "
1846 "BUILTIN\\Administrators during join: %s\n",
1847 nt_errstr(status
)));
1851 /****************************************************************
1852 ****************************************************************/
1854 static WERROR
libnet_join_post_processing(TALLOC_CTX
*mem_ctx
,
1855 struct libnet_JoinCtx
*r
)
1859 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1860 return r
->out
.result
;
1863 werr
= do_JoinConfig(r
);
1864 if (!W_ERROR_IS_OK(werr
)) {
1868 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1872 saf_join_store(r
->out
.netbios_domain_name
, r
->in
.dc_name
);
1873 if (r
->out
.dns_domain_name
) {
1874 saf_join_store(r
->out
.dns_domain_name
, r
->in
.dc_name
);
1878 if (r
->out
.domain_is_ad
&&
1879 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1880 ADS_STATUS ads_status
;
1882 ads_status
= libnet_join_post_processing_ads(mem_ctx
, r
);
1883 if (!ADS_ERR_OK(ads_status
)) {
1884 return WERR_GENERAL_FAILURE
;
1887 #endif /* HAVE_ADS */
1889 libnet_join_add_dom_rids_to_builtins(r
->out
.domain_sid
);
1894 /****************************************************************
1895 ****************************************************************/
1897 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx
*r
)
1900 ads_destroy(&r
->in
.ads
);
1906 /****************************************************************
1907 ****************************************************************/
1909 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx
*r
)
1912 ads_destroy(&r
->in
.ads
);
1918 /****************************************************************
1919 ****************************************************************/
1921 WERROR
libnet_init_JoinCtx(TALLOC_CTX
*mem_ctx
,
1922 struct libnet_JoinCtx
**r
)
1924 struct libnet_JoinCtx
*ctx
;
1926 ctx
= talloc_zero(mem_ctx
, struct libnet_JoinCtx
);
1931 talloc_set_destructor(ctx
, libnet_destroy_JoinCtx
);
1933 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, lp_netbios_name());
1934 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1936 ctx
->in
.secure_channel_type
= SEC_CHAN_WKSTA
;
1943 /****************************************************************
1944 ****************************************************************/
1946 WERROR
libnet_init_UnjoinCtx(TALLOC_CTX
*mem_ctx
,
1947 struct libnet_UnjoinCtx
**r
)
1949 struct libnet_UnjoinCtx
*ctx
;
1951 ctx
= talloc_zero(mem_ctx
, struct libnet_UnjoinCtx
);
1956 talloc_set_destructor(ctx
, libnet_destroy_UnjoinCtx
);
1958 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, lp_netbios_name());
1959 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1966 /****************************************************************
1967 ****************************************************************/
1969 static WERROR
libnet_join_check_config(TALLOC_CTX
*mem_ctx
,
1970 struct libnet_JoinCtx
*r
)
1972 bool valid_security
= false;
1973 bool valid_workgroup
= false;
1974 bool valid_realm
= false;
1976 /* check if configuration is already set correctly */
1978 valid_workgroup
= strequal(lp_workgroup(), r
->out
.netbios_domain_name
);
1980 switch (r
->out
.domain_is_ad
) {
1982 valid_security
= (lp_security() == SEC_DOMAIN
);
1983 if (valid_workgroup
&& valid_security
) {
1984 /* nothing to be done */
1989 valid_realm
= strequal(lp_realm(), r
->out
.dns_domain_name
);
1990 switch (lp_security()) {
1993 valid_security
= true;
1996 if (valid_workgroup
&& valid_realm
&& valid_security
) {
1997 /* nothing to be done */
2003 /* check if we are supposed to manipulate configuration */
2005 if (!r
->in
.modify_config
) {
2007 char *wrong_conf
= talloc_strdup(mem_ctx
, "");
2009 if (!valid_workgroup
) {
2010 wrong_conf
= talloc_asprintf_append(wrong_conf
,
2011 "\"workgroup\" set to '%s', should be '%s'",
2012 lp_workgroup(), r
->out
.netbios_domain_name
);
2013 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
2017 wrong_conf
= talloc_asprintf_append(wrong_conf
,
2018 "\"realm\" set to '%s', should be '%s'",
2019 lp_realm(), r
->out
.dns_domain_name
);
2020 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
2023 if (!valid_security
) {
2024 const char *sec
= NULL
;
2025 switch (lp_security()) {
2026 case SEC_USER
: sec
= "user"; break;
2027 case SEC_DOMAIN
: sec
= "domain"; break;
2028 case SEC_ADS
: sec
= "ads"; break;
2030 wrong_conf
= talloc_asprintf_append(wrong_conf
,
2031 "\"security\" set to '%s', should be %s",
2032 sec
, r
->out
.domain_is_ad
?
2033 "either 'domain' or 'ads'" : "'domain'");
2034 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
2037 libnet_join_set_error_string(mem_ctx
, r
,
2038 "Invalid configuration (%s) and configuration modification "
2039 "was not requested", wrong_conf
);
2040 return WERR_CAN_NOT_COMPLETE
;
2043 /* check if we are able to manipulate configuration */
2045 if (!lp_config_backend_is_registry()) {
2046 libnet_join_set_error_string(mem_ctx
, r
,
2047 "Configuration manipulation requested but not "
2048 "supported by backend");
2049 return WERR_NOT_SUPPORTED
;
2055 /****************************************************************
2056 ****************************************************************/
2058 static WERROR
libnet_DomainJoin(TALLOC_CTX
*mem_ctx
,
2059 struct libnet_JoinCtx
*r
)
2063 struct cli_state
*cli
= NULL
;
2065 ADS_STATUS ads_status
;
2066 #endif /* HAVE_ADS */
2068 if (!r
->in
.dc_name
) {
2069 struct netr_DsRGetDCNameInfo
*info
;
2071 status
= dsgetdcname(mem_ctx
,
2076 DS_FORCE_REDISCOVERY
|
2077 DS_DIRECTORY_SERVICE_REQUIRED
|
2078 DS_WRITABLE_REQUIRED
|
2081 if (!NT_STATUS_IS_OK(status
)) {
2082 libnet_join_set_error_string(mem_ctx
, r
,
2083 "failed to find DC for domain %s",
2085 get_friendly_nt_error_msg(status
));
2086 return WERR_DCNOTFOUND
;
2089 dc
= strip_hostname(info
->dc_unc
);
2090 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
2091 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
2094 status
= libnet_join_lookup_dc_rpc(mem_ctx
, r
, &cli
);
2095 if (!NT_STATUS_IS_OK(status
)) {
2096 libnet_join_set_error_string(mem_ctx
, r
,
2097 "failed to lookup DC info for domain '%s' over rpc: %s",
2098 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
2099 return ntstatus_to_werror(status
);
2102 werr
= libnet_join_check_config(mem_ctx
, r
);
2103 if (!W_ERROR_IS_OK(werr
)) {
2109 create_local_private_krb5_conf_for_domain(
2110 r
->out
.dns_domain_name
, r
->out
.netbios_domain_name
,
2111 NULL
, smbXcli_conn_remote_sockaddr(cli
->conn
),
2112 smbXcli_conn_remote_name(cli
->conn
));
2114 if (r
->out
.domain_is_ad
&& r
->in
.account_ou
&&
2115 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
2117 ads_status
= libnet_join_connect_ads(mem_ctx
, r
);
2118 if (!ADS_ERR_OK(ads_status
)) {
2119 return WERR_DEFAULT_JOIN_REQUIRED
;
2122 ads_status
= libnet_join_precreate_machine_acct(mem_ctx
, r
);
2123 if (!ADS_ERR_OK(ads_status
)) {
2124 libnet_join_set_error_string(mem_ctx
, r
,
2125 "failed to precreate account in ou %s: %s",
2127 ads_errstr(ads_status
));
2128 return WERR_DEFAULT_JOIN_REQUIRED
;
2131 r
->in
.join_flags
&= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
;
2133 #endif /* HAVE_ADS */
2135 if ((r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
) &&
2136 (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED
)) {
2137 status
= libnet_join_joindomain_rpc_unsecure(mem_ctx
, r
, cli
);
2139 status
= libnet_join_joindomain_rpc(mem_ctx
, r
, cli
);
2141 if (!NT_STATUS_IS_OK(status
)) {
2142 libnet_join_set_error_string(mem_ctx
, r
,
2143 "failed to join domain '%s' over rpc: %s",
2144 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
2145 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
2146 return WERR_SETUP_ALREADY_JOINED
;
2148 werr
= ntstatus_to_werror(status
);
2152 if (!libnet_join_joindomain_store_secrets(mem_ctx
, r
)) {
2153 werr
= WERR_SETUP_NOT_JOINED
;
2167 /****************************************************************
2168 ****************************************************************/
2170 static WERROR
libnet_join_rollback(TALLOC_CTX
*mem_ctx
,
2171 struct libnet_JoinCtx
*r
)
2174 struct libnet_UnjoinCtx
*u
= NULL
;
2176 werr
= libnet_init_UnjoinCtx(mem_ctx
, &u
);
2177 if (!W_ERROR_IS_OK(werr
)) {
2181 u
->in
.debug
= r
->in
.debug
;
2182 u
->in
.dc_name
= r
->in
.dc_name
;
2183 u
->in
.domain_name
= r
->in
.domain_name
;
2184 u
->in
.admin_account
= r
->in
.admin_account
;
2185 u
->in
.admin_password
= r
->in
.admin_password
;
2186 u
->in
.modify_config
= r
->in
.modify_config
;
2187 u
->in
.use_kerberos
= r
->in
.use_kerberos
;
2188 u
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
2189 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
2191 werr
= libnet_Unjoin(mem_ctx
, u
);
2197 /****************************************************************
2198 ****************************************************************/
2200 WERROR
libnet_Join(TALLOC_CTX
*mem_ctx
,
2201 struct libnet_JoinCtx
*r
)
2206 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx
, r
);
2209 ZERO_STRUCT(r
->out
);
2211 werr
= libnet_join_pre_processing(mem_ctx
, r
);
2212 if (!W_ERROR_IS_OK(werr
)) {
2216 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2217 werr
= libnet_DomainJoin(mem_ctx
, r
);
2218 if (!W_ERROR_IS_OK(werr
)) {
2223 werr
= libnet_join_post_processing(mem_ctx
, r
);
2224 if (!W_ERROR_IS_OK(werr
)) {
2228 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2229 werr
= libnet_join_post_verify(mem_ctx
, r
);
2230 if (!W_ERROR_IS_OK(werr
)) {
2231 libnet_join_rollback(mem_ctx
, r
);
2236 r
->out
.result
= werr
;
2239 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx
, r
);
2244 /****************************************************************
2245 ****************************************************************/
2247 static WERROR
libnet_DomainUnjoin(TALLOC_CTX
*mem_ctx
,
2248 struct libnet_UnjoinCtx
*r
)
2252 if (!r
->in
.domain_sid
) {
2254 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid
)) {
2255 libnet_unjoin_set_error_string(mem_ctx
, r
,
2256 "Unable to fetch domain sid: are we joined?");
2257 return WERR_SETUP_NOT_JOINED
;
2259 r
->in
.domain_sid
= dom_sid_dup(mem_ctx
, &sid
);
2260 W_ERROR_HAVE_NO_MEMORY(r
->in
.domain_sid
);
2263 if (!(r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) &&
2264 !r
->in
.delete_machine_account
) {
2265 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2269 if (!r
->in
.dc_name
) {
2270 struct netr_DsRGetDCNameInfo
*info
;
2272 status
= dsgetdcname(mem_ctx
,
2277 DS_DIRECTORY_SERVICE_REQUIRED
|
2278 DS_WRITABLE_REQUIRED
|
2281 if (!NT_STATUS_IS_OK(status
)) {
2282 libnet_unjoin_set_error_string(mem_ctx
, r
,
2283 "failed to find DC for domain %s",
2285 get_friendly_nt_error_msg(status
));
2286 return WERR_DCNOTFOUND
;
2289 dc
= strip_hostname(info
->dc_unc
);
2290 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
2291 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
2295 /* for net ads leave, try to delete the account. If it works,
2296 no sense in disabling. If it fails, we can still try to
2299 if (r
->in
.delete_machine_account
) {
2300 ADS_STATUS ads_status
;
2301 ads_status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
2302 if (ADS_ERR_OK(ads_status
)) {
2304 r
->out
.dns_domain_name
=
2305 talloc_strdup(mem_ctx
,
2306 r
->in
.ads
->server
.realm
);
2308 libnet_unjoin_remove_machine_acct(mem_ctx
, r
);
2310 if (!ADS_ERR_OK(ads_status
)) {
2311 libnet_unjoin_set_error_string(mem_ctx
, r
,
2312 "failed to remove machine account from AD: %s",
2313 ads_errstr(ads_status
));
2315 r
->out
.deleted_machine_account
= true;
2316 W_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
2317 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2321 #endif /* HAVE_ADS */
2323 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2325 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) {
2326 status
= libnet_join_unjoindomain_rpc(mem_ctx
, r
);
2327 if (!NT_STATUS_IS_OK(status
)) {
2328 libnet_unjoin_set_error_string(mem_ctx
, r
,
2329 "failed to disable machine account via rpc: %s",
2330 get_friendly_nt_error_msg(status
));
2331 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
2332 return WERR_SETUP_NOT_JOINED
;
2334 return ntstatus_to_werror(status
);
2337 r
->out
.disabled_machine_account
= true;
2340 /* If disable succeeded or was not requested at all, we
2341 should be getting rid of our end of things */
2343 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2348 /****************************************************************
2349 ****************************************************************/
2351 static WERROR
libnet_unjoin_pre_processing(TALLOC_CTX
*mem_ctx
,
2352 struct libnet_UnjoinCtx
*r
)
2354 if (!r
->in
.domain_name
) {
2355 libnet_unjoin_set_error_string(mem_ctx
, r
,
2356 "No domain name defined");
2357 return WERR_INVALID_PARAM
;
2360 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
2363 libnet_unjoin_set_error_string(mem_ctx
, r
,
2364 "Failed to parse domain name");
2365 return WERR_INVALID_PARAM
;
2369 return WERR_SETUP_DOMAIN_CONTROLLER
;
2372 if (!secrets_init()) {
2373 libnet_unjoin_set_error_string(mem_ctx
, r
,
2374 "Unable to open secrets database");
2375 return WERR_CAN_NOT_COMPLETE
;
2381 /****************************************************************
2382 ****************************************************************/
2384 static WERROR
libnet_unjoin_post_processing(TALLOC_CTX
*mem_ctx
,
2385 struct libnet_UnjoinCtx
*r
)
2387 saf_delete(r
->out
.netbios_domain_name
);
2388 saf_delete(r
->out
.dns_domain_name
);
2390 return libnet_unjoin_config(r
);
2393 /****************************************************************
2394 ****************************************************************/
2396 WERROR
libnet_Unjoin(TALLOC_CTX
*mem_ctx
,
2397 struct libnet_UnjoinCtx
*r
)
2402 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx
, r
);
2405 werr
= libnet_unjoin_pre_processing(mem_ctx
, r
);
2406 if (!W_ERROR_IS_OK(werr
)) {
2410 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2411 werr
= libnet_DomainUnjoin(mem_ctx
, r
);
2412 if (!W_ERROR_IS_OK(werr
)) {
2413 libnet_unjoin_config(r
);
2418 werr
= libnet_unjoin_post_processing(mem_ctx
, r
);
2419 if (!W_ERROR_IS_OK(werr
)) {
2424 r
->out
.result
= werr
;
2427 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx
, r
);