2 * Unix SMB/CIFS implementation.
4 * Copyright (C) Gerald (Jerry) Carter 2006
5 * Copyright (C) Guenther Deschner 2007-2008
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "libnet/libnet.h"
23 #include "libcli/auth/libcli_auth.h"
24 #include "../librpc/gen_ndr/cli_samr.h"
25 #include "../librpc/gen_ndr/cli_lsa.h"
27 /****************************************************************
28 ****************************************************************/
30 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
33 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
34 DEBUG(1,("libnet_Join:\n%s", str)); \
38 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
39 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
40 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
41 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
43 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
46 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
47 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
51 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
52 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
53 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
54 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
56 /****************************************************************
57 ****************************************************************/
59 static void libnet_join_set_error_string(TALLOC_CTX
*mem_ctx
,
60 struct libnet_JoinCtx
*r
,
61 const char *format
, ...)
65 if (r
->out
.error_string
) {
69 va_start(args
, format
);
70 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
74 /****************************************************************
75 ****************************************************************/
77 static void libnet_unjoin_set_error_string(TALLOC_CTX
*mem_ctx
,
78 struct libnet_UnjoinCtx
*r
,
79 const char *format
, ...)
83 if (r
->out
.error_string
) {
87 va_start(args
, format
);
88 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
94 /****************************************************************
95 ****************************************************************/
97 static ADS_STATUS
libnet_connect_ads(const char *dns_domain_name
,
98 const char *netbios_domain_name
,
100 const char *user_name
,
101 const char *password
,
105 ADS_STRUCT
*my_ads
= NULL
;
107 my_ads
= ads_init(dns_domain_name
,
111 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
115 SAFE_FREE(my_ads
->auth
.user_name
);
116 my_ads
->auth
.user_name
= SMB_STRDUP(user_name
);
120 SAFE_FREE(my_ads
->auth
.password
);
121 my_ads
->auth
.password
= SMB_STRDUP(password
);
124 status
= ads_connect_user_creds(my_ads
);
125 if (!ADS_ERR_OK(status
)) {
126 ads_destroy(&my_ads
);
134 /****************************************************************
135 ****************************************************************/
137 static ADS_STATUS
libnet_join_connect_ads(TALLOC_CTX
*mem_ctx
,
138 struct libnet_JoinCtx
*r
)
142 status
= libnet_connect_ads(r
->out
.dns_domain_name
,
143 r
->out
.netbios_domain_name
,
146 r
->in
.admin_password
,
148 if (!ADS_ERR_OK(status
)) {
149 libnet_join_set_error_string(mem_ctx
, r
,
150 "failed to connect to AD: %s",
155 if (!r
->out
.netbios_domain_name
) {
156 r
->out
.netbios_domain_name
= talloc_strdup(mem_ctx
,
157 r
->in
.ads
->server
.workgroup
);
158 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.netbios_domain_name
);
161 if (!r
->out
.dns_domain_name
) {
162 r
->out
.dns_domain_name
= talloc_strdup(mem_ctx
,
163 r
->in
.ads
->config
.realm
);
164 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
167 r
->out
.domain_is_ad
= true;
172 /****************************************************************
173 ****************************************************************/
175 static ADS_STATUS
libnet_unjoin_connect_ads(TALLOC_CTX
*mem_ctx
,
176 struct libnet_UnjoinCtx
*r
)
180 status
= libnet_connect_ads(r
->in
.domain_name
,
184 r
->in
.admin_password
,
186 if (!ADS_ERR_OK(status
)) {
187 libnet_unjoin_set_error_string(mem_ctx
, r
,
188 "failed to connect to AD: %s",
195 /****************************************************************
196 join a domain using ADS (LDAP mods)
197 ****************************************************************/
199 static ADS_STATUS
libnet_join_precreate_machine_acct(TALLOC_CTX
*mem_ctx
,
200 struct libnet_JoinCtx
*r
)
203 LDAPMessage
*res
= NULL
;
204 const char *attrs
[] = { "dn", NULL
};
207 status
= ads_check_ou_dn(mem_ctx
, r
->in
.ads
, &r
->in
.account_ou
);
208 if (!ADS_ERR_OK(status
)) {
212 status
= ads_search_dn(r
->in
.ads
, &res
, r
->in
.account_ou
, attrs
);
213 if (!ADS_ERR_OK(status
)) {
217 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
218 ads_msgfree(r
->in
.ads
, res
);
219 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT
);
222 ads_msgfree(r
->in
.ads
, res
);
224 /* Attempt to create the machine account and bail if this fails.
225 Assume that the admin wants exactly what they requested */
227 status
= ads_create_machine_acct(r
->in
.ads
,
231 if (ADS_ERR_OK(status
)) {
232 DEBUG(1,("machine account creation created\n"));
234 } else if ((status
.error_type
== ENUM_ADS_ERROR_LDAP
) &&
235 (status
.err
.rc
== LDAP_ALREADY_EXISTS
)) {
236 status
= ADS_SUCCESS
;
239 if (!ADS_ERR_OK(status
)) {
240 DEBUG(1,("machine account creation failed\n"));
244 status
= ads_move_machine_acct(r
->in
.ads
,
248 if (!ADS_ERR_OK(status
)) {
249 DEBUG(1,("failure to locate/move pre-existing "
250 "machine account\n"));
254 DEBUG(1,("The machine account %s the specified OU.\n",
255 moved
? "was moved into" : "already exists in"));
260 /****************************************************************
261 ****************************************************************/
263 static ADS_STATUS
libnet_unjoin_remove_machine_acct(TALLOC_CTX
*mem_ctx
,
264 struct libnet_UnjoinCtx
*r
)
269 status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
270 if (!ADS_ERR_OK(status
)) {
271 libnet_unjoin_set_error_string(mem_ctx
, r
,
272 "failed to connect to AD: %s",
278 status
= ads_leave_realm(r
->in
.ads
, r
->in
.machine_name
);
279 if (!ADS_ERR_OK(status
)) {
280 libnet_unjoin_set_error_string(mem_ctx
, r
,
281 "failed to leave realm: %s",
289 /****************************************************************
290 ****************************************************************/
292 static ADS_STATUS
libnet_join_find_machine_acct(TALLOC_CTX
*mem_ctx
,
293 struct libnet_JoinCtx
*r
)
296 LDAPMessage
*res
= NULL
;
299 if (!r
->in
.machine_name
) {
300 return ADS_ERROR(LDAP_NO_MEMORY
);
303 status
= ads_find_machine_acct(r
->in
.ads
,
306 if (!ADS_ERR_OK(status
)) {
310 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
311 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
315 dn
= ads_get_dn(r
->in
.ads
, mem_ctx
, res
);
317 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
321 r
->out
.dn
= talloc_strdup(mem_ctx
, dn
);
323 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
328 ads_msgfree(r
->in
.ads
, res
);
334 /****************************************************************
335 Set a machines dNSHostName and servicePrincipalName attributes
336 ****************************************************************/
338 static ADS_STATUS
libnet_join_set_machine_spn(TALLOC_CTX
*mem_ctx
,
339 struct libnet_JoinCtx
*r
)
344 const char *spn_array
[3] = {NULL
, NULL
, NULL
};
349 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
350 if (!ADS_ERR_OK(status
)) {
354 /* Windows only creates HOST/shortname & HOST/fqdn. */
356 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", r
->in
.machine_name
);
358 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
363 if (!name_to_fqdn(my_fqdn
, r
->in
.machine_name
)
364 || (strchr(my_fqdn
, '.') == NULL
)) {
365 fstr_sprintf(my_fqdn
, "%s.%s", r
->in
.machine_name
,
366 r
->out
.dns_domain_name
);
371 if (!strequal(my_fqdn
, r
->in
.machine_name
)) {
372 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", my_fqdn
);
374 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
379 mods
= ads_init_mods(mem_ctx
);
381 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
384 /* fields of primary importance */
386 status
= ads_mod_str(mem_ctx
, &mods
, "dNSHostName", my_fqdn
);
387 if (!ADS_ERR_OK(status
)) {
388 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
391 status
= ads_mod_strlist(mem_ctx
, &mods
, "servicePrincipalName",
393 if (!ADS_ERR_OK(status
)) {
394 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
397 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
400 /****************************************************************
401 ****************************************************************/
403 static ADS_STATUS
libnet_join_set_machine_upn(TALLOC_CTX
*mem_ctx
,
404 struct libnet_JoinCtx
*r
)
409 if (!r
->in
.create_upn
) {
415 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
416 if (!ADS_ERR_OK(status
)) {
421 r
->in
.upn
= talloc_asprintf(mem_ctx
,
424 r
->out
.dns_domain_name
);
426 return ADS_ERROR(LDAP_NO_MEMORY
);
430 /* now do the mods */
432 mods
= ads_init_mods(mem_ctx
);
434 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
437 /* fields of primary importance */
439 status
= ads_mod_str(mem_ctx
, &mods
, "userPrincipalName", r
->in
.upn
);
440 if (!ADS_ERR_OK(status
)) {
441 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
444 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
448 /****************************************************************
449 ****************************************************************/
451 static ADS_STATUS
libnet_join_set_os_attributes(TALLOC_CTX
*mem_ctx
,
452 struct libnet_JoinCtx
*r
)
458 if (!r
->in
.os_name
|| !r
->in
.os_version
) {
464 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
465 if (!ADS_ERR_OK(status
)) {
469 /* now do the mods */
471 mods
= ads_init_mods(mem_ctx
);
473 return ADS_ERROR(LDAP_NO_MEMORY
);
476 os_sp
= talloc_asprintf(mem_ctx
, "Samba %s", samba_version_string());
478 return ADS_ERROR(LDAP_NO_MEMORY
);
481 /* fields of primary importance */
483 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystem",
485 if (!ADS_ERR_OK(status
)) {
489 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemVersion",
491 if (!ADS_ERR_OK(status
)) {
495 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemServicePack",
497 if (!ADS_ERR_OK(status
)) {
501 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
504 /****************************************************************
505 ****************************************************************/
507 static bool libnet_join_create_keytab(TALLOC_CTX
*mem_ctx
,
508 struct libnet_JoinCtx
*r
)
510 if (!USE_SYSTEM_KEYTAB
) {
514 if (ads_keytab_create_default(r
->in
.ads
) != 0) {
521 /****************************************************************
522 ****************************************************************/
524 static bool libnet_join_derive_salting_principal(TALLOC_CTX
*mem_ctx
,
525 struct libnet_JoinCtx
*r
)
527 uint32_t domain_func
;
529 const char *salt
= NULL
;
530 char *std_salt
= NULL
;
532 status
= ads_domain_func_level(r
->in
.ads
, &domain_func
);
533 if (!ADS_ERR_OK(status
)) {
534 libnet_join_set_error_string(mem_ctx
, r
,
535 "failed to determine domain functional level: %s",
540 /* go ahead and setup the default salt */
542 std_salt
= kerberos_standard_des_salt();
544 libnet_join_set_error_string(mem_ctx
, r
,
545 "failed to obtain standard DES salt");
549 salt
= talloc_strdup(mem_ctx
, std_salt
);
556 /* if it's a Windows functional domain, we have to look for the UPN */
558 if (domain_func
== DS_DOMAIN_FUNCTION_2000
) {
561 upn
= ads_get_upn(r
->in
.ads
, mem_ctx
,
564 salt
= talloc_strdup(mem_ctx
, upn
);
571 return kerberos_secrets_store_des_salt(salt
);
574 /****************************************************************
575 ****************************************************************/
577 static ADS_STATUS
libnet_join_post_processing_ads(TALLOC_CTX
*mem_ctx
,
578 struct libnet_JoinCtx
*r
)
583 status
= libnet_join_connect_ads(mem_ctx
, r
);
584 if (!ADS_ERR_OK(status
)) {
589 status
= libnet_join_set_machine_spn(mem_ctx
, r
);
590 if (!ADS_ERR_OK(status
)) {
591 libnet_join_set_error_string(mem_ctx
, r
,
592 "failed to set machine spn: %s",
597 status
= libnet_join_set_os_attributes(mem_ctx
, r
);
598 if (!ADS_ERR_OK(status
)) {
599 libnet_join_set_error_string(mem_ctx
, r
,
600 "failed to set machine os attributes: %s",
605 status
= libnet_join_set_machine_upn(mem_ctx
, r
);
606 if (!ADS_ERR_OK(status
)) {
607 libnet_join_set_error_string(mem_ctx
, r
,
608 "failed to set machine upn: %s",
613 if (!libnet_join_derive_salting_principal(mem_ctx
, r
)) {
614 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
617 if (!libnet_join_create_keytab(mem_ctx
, r
)) {
618 libnet_join_set_error_string(mem_ctx
, r
,
619 "failed to create kerberos keytab");
620 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
625 #endif /* WITH_ADS */
627 /****************************************************************
628 Store the machine password and domain SID
629 ****************************************************************/
631 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX
*mem_ctx
,
632 struct libnet_JoinCtx
*r
)
634 if (!secrets_store_domain_sid(r
->out
.netbios_domain_name
,
637 DEBUG(1,("Failed to save domain sid\n"));
641 if (!secrets_store_machine_password(r
->in
.machine_password
,
642 r
->out
.netbios_domain_name
,
643 r
->in
.secure_channel_type
))
645 DEBUG(1,("Failed to save machine password\n"));
652 /****************************************************************
653 Connect dc's IPC$ share
654 ****************************************************************/
656 static NTSTATUS
libnet_join_connect_dc_ipc(const char *dc
,
660 struct cli_state
**cli
)
665 flags
|= CLI_FULL_CONNECTION_USE_KERBEROS
;
668 if (use_kerberos
&& pass
) {
669 flags
|= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS
;
672 return cli_full_connection(cli
, NULL
,
683 /****************************************************************
684 Lookup domain dc's info
685 ****************************************************************/
687 static NTSTATUS
libnet_join_lookup_dc_rpc(TALLOC_CTX
*mem_ctx
,
688 struct libnet_JoinCtx
*r
,
689 struct cli_state
**cli
)
691 struct rpc_pipe_client
*pipe_hnd
= NULL
;
692 struct policy_handle lsa_pol
;
693 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
694 union lsa_PolicyInformation
*info
= NULL
;
696 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
698 r
->in
.admin_password
,
701 if (!NT_STATUS_IS_OK(status
)) {
705 status
= cli_rpc_pipe_open_noauth(*cli
, &ndr_table_lsarpc
.syntax_id
,
707 if (!NT_STATUS_IS_OK(status
)) {
708 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
713 status
= rpccli_lsa_open_policy(pipe_hnd
, mem_ctx
, true,
714 SEC_FLAG_MAXIMUM_ALLOWED
, &lsa_pol
);
715 if (!NT_STATUS_IS_OK(status
)) {
719 status
= rpccli_lsa_QueryInfoPolicy2(pipe_hnd
, mem_ctx
,
723 if (NT_STATUS_IS_OK(status
)) {
724 r
->out
.domain_is_ad
= true;
725 r
->out
.netbios_domain_name
= info
->dns
.name
.string
;
726 r
->out
.dns_domain_name
= info
->dns
.dns_domain
.string
;
727 r
->out
.forest_name
= info
->dns
.dns_forest
.string
;
728 r
->out
.domain_sid
= sid_dup_talloc(mem_ctx
, info
->dns
.sid
);
729 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
732 if (!NT_STATUS_IS_OK(status
)) {
733 status
= rpccli_lsa_QueryInfoPolicy(pipe_hnd
, mem_ctx
,
735 LSA_POLICY_INFO_ACCOUNT_DOMAIN
,
737 if (!NT_STATUS_IS_OK(status
)) {
741 r
->out
.netbios_domain_name
= info
->account_domain
.name
.string
;
742 r
->out
.domain_sid
= sid_dup_talloc(mem_ctx
, info
->account_domain
.sid
);
743 NT_STATUS_HAVE_NO_MEMORY(r
->out
.domain_sid
);
746 rpccli_lsa_Close(pipe_hnd
, mem_ctx
, &lsa_pol
);
747 TALLOC_FREE(pipe_hnd
);
753 /****************************************************************
754 Do the domain join unsecure
755 ****************************************************************/
757 static NTSTATUS
libnet_join_joindomain_rpc_unsecure(TALLOC_CTX
*mem_ctx
,
758 struct libnet_JoinCtx
*r
,
759 struct cli_state
*cli
)
761 struct rpc_pipe_client
*pipe_hnd
= NULL
;
762 unsigned char orig_trust_passwd_hash
[16];
763 unsigned char new_trust_passwd_hash
[16];
764 fstring trust_passwd
;
767 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_netlogon
.syntax_id
,
769 if (!NT_STATUS_IS_OK(status
)) {
773 if (!r
->in
.machine_password
) {
774 r
->in
.machine_password
= generate_random_str(mem_ctx
, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
775 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
778 E_md4hash(r
->in
.machine_password
, new_trust_passwd_hash
);
780 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
781 fstrcpy(trust_passwd
, r
->in
.admin_password
);
782 strlower_m(trust_passwd
);
785 * Machine names can be 15 characters, but the max length on
786 * a password is 14. --jerry
789 trust_passwd
[14] = '\0';
791 E_md4hash(trust_passwd
, orig_trust_passwd_hash
);
793 status
= rpccli_netlogon_set_trust_password(pipe_hnd
, mem_ctx
,
795 orig_trust_passwd_hash
,
796 r
->in
.machine_password
,
797 new_trust_passwd_hash
,
798 r
->in
.secure_channel_type
);
803 /****************************************************************
805 ****************************************************************/
807 static NTSTATUS
libnet_join_joindomain_rpc(TALLOC_CTX
*mem_ctx
,
808 struct libnet_JoinCtx
*r
,
809 struct cli_state
*cli
)
811 struct rpc_pipe_client
*pipe_hnd
= NULL
;
812 struct policy_handle sam_pol
, domain_pol
, user_pol
;
813 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
815 struct lsa_String lsa_acct_name
;
817 uint32_t acct_flags
= ACB_WSTRUST
;
818 struct samr_Ids user_rids
;
819 struct samr_Ids name_types
;
820 union samr_UserInfo user_info
;
822 struct samr_CryptPassword crypt_pwd
;
823 struct samr_CryptPasswordEx crypt_pwd_ex
;
825 ZERO_STRUCT(sam_pol
);
826 ZERO_STRUCT(domain_pol
);
827 ZERO_STRUCT(user_pol
);
829 switch (r
->in
.secure_channel_type
) {
831 acct_flags
= ACB_WSTRUST
;
834 acct_flags
= ACB_SVRTRUST
;
837 return NT_STATUS_INVALID_PARAMETER
;
840 if (!r
->in
.machine_password
) {
841 r
->in
.machine_password
= generate_random_str(mem_ctx
, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
);
842 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
845 /* Open the domain */
847 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
849 if (!NT_STATUS_IS_OK(status
)) {
850 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
855 status
= rpccli_samr_Connect2(pipe_hnd
, mem_ctx
,
857 SAMR_ACCESS_ENUM_DOMAINS
858 | SAMR_ACCESS_LOOKUP_DOMAIN
,
860 if (!NT_STATUS_IS_OK(status
)) {
864 status
= rpccli_samr_OpenDomain(pipe_hnd
, mem_ctx
,
866 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
867 | SAMR_DOMAIN_ACCESS_CREATE_USER
868 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT
,
871 if (!NT_STATUS_IS_OK(status
)) {
875 /* Create domain user */
877 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
878 strlower_m(acct_name
);
880 init_lsa_String(&lsa_acct_name
, acct_name
);
882 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
) {
883 uint32_t access_desired
=
884 SEC_GENERIC_READ
| SEC_GENERIC_WRITE
| SEC_GENERIC_EXECUTE
|
885 SEC_STD_WRITE_DAC
| SEC_STD_DELETE
|
886 SAMR_USER_ACCESS_SET_PASSWORD
|
887 SAMR_USER_ACCESS_GET_ATTRIBUTES
|
888 SAMR_USER_ACCESS_SET_ATTRIBUTES
;
889 uint32_t access_granted
= 0;
891 DEBUG(10,("Creating account with desired access mask: %d\n",
894 status
= rpccli_samr_CreateUser2(pipe_hnd
, mem_ctx
,
902 if (!NT_STATUS_IS_OK(status
) &&
903 !NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
905 DEBUG(10,("Creation of workstation account failed: %s\n",
908 /* If NT_STATUS_ACCESS_DENIED then we have a valid
909 username/password combo but the user does not have
910 administrator access. */
912 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
913 libnet_join_set_error_string(mem_ctx
, r
,
914 "User specified does not have "
915 "administrator privileges");
921 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
922 if (!(r
->in
.join_flags
&
923 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
)) {
928 /* We *must* do this.... don't ask... */
930 if (NT_STATUS_IS_OK(status
)) {
931 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
935 status
= rpccli_samr_LookupNames(pipe_hnd
, mem_ctx
,
941 if (!NT_STATUS_IS_OK(status
)) {
945 if (name_types
.ids
[0] != SID_NAME_USER
) {
946 DEBUG(0,("%s is not a user account (type=%d)\n",
947 acct_name
, name_types
.ids
[0]));
948 status
= NT_STATUS_INVALID_WORKSTATION
;
952 user_rid
= user_rids
.ids
[0];
954 /* Open handle on user */
956 status
= rpccli_samr_OpenUser(pipe_hnd
, mem_ctx
,
958 SEC_FLAG_MAXIMUM_ALLOWED
,
961 if (!NT_STATUS_IS_OK(status
)) {
965 /* Fill in the additional account flags now */
967 acct_flags
|= ACB_PWNOEXP
;
968 if (r
->out
.domain_is_ad
) {
969 #if !defined(ENCTYPE_ARCFOUR_HMAC)
970 acct_flags
|= ACB_USE_DES_KEY_ONLY
;
975 /* Set account flags on machine account */
976 ZERO_STRUCT(user_info
.info16
);
977 user_info
.info16
.acct_flags
= acct_flags
;
979 status
= rpccli_samr_SetUserInfo(pipe_hnd
, mem_ctx
,
984 if (!NT_STATUS_IS_OK(status
)) {
986 rpccli_samr_DeleteUser(pipe_hnd
, mem_ctx
,
989 libnet_join_set_error_string(mem_ctx
, r
,
990 "Failed to set account flags for machine account (%s)\n",
995 /* Set password on machine account - first try level 26 */
997 init_samr_CryptPasswordEx(r
->in
.machine_password
,
998 &cli
->user_session_key
,
1001 user_info
.info26
.password
= crypt_pwd_ex
;
1002 user_info
.info26
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1004 status
= rpccli_samr_SetUserInfo2(pipe_hnd
, mem_ctx
,
1009 if (NT_STATUS_EQUAL(status
, NT_STATUS(DCERPC_FAULT_INVALID_TAG
))) {
1011 /* retry with level 24 */
1013 init_samr_CryptPassword(r
->in
.machine_password
,
1014 &cli
->user_session_key
,
1017 user_info
.info24
.password
= crypt_pwd
;
1018 user_info
.info24
.password_expired
= PASS_DONT_CHANGE_AT_NEXT_LOGON
;
1020 status
= rpccli_samr_SetUserInfo2(pipe_hnd
, mem_ctx
,
1026 if (!NT_STATUS_IS_OK(status
)) {
1028 rpccli_samr_DeleteUser(pipe_hnd
, mem_ctx
,
1031 libnet_join_set_error_string(mem_ctx
, r
,
1032 "Failed to set password for machine account (%s)\n",
1037 status
= NT_STATUS_OK
;
1044 if (is_valid_policy_hnd(&sam_pol
)) {
1045 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &sam_pol
);
1047 if (is_valid_policy_hnd(&domain_pol
)) {
1048 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &domain_pol
);
1050 if (is_valid_policy_hnd(&user_pol
)) {
1051 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1053 TALLOC_FREE(pipe_hnd
);
1058 /****************************************************************
1059 ****************************************************************/
1061 NTSTATUS
libnet_join_ok(const char *netbios_domain_name
,
1062 const char *machine_name
,
1063 const char *dc_name
)
1065 uint32_t neg_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
1066 struct cli_state
*cli
= NULL
;
1067 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1068 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1070 char *machine_password
= NULL
;
1071 char *machine_account
= NULL
;
1074 return NT_STATUS_INVALID_PARAMETER
;
1077 if (!secrets_init()) {
1078 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1081 machine_password
= secrets_fetch_machine_password(netbios_domain_name
,
1083 if (!machine_password
) {
1084 return NT_STATUS_NO_TRUST_LSA_SECRET
;
1087 if (asprintf(&machine_account
, "%s$", machine_name
) == -1) {
1088 SAFE_FREE(machine_password
);
1089 return NT_STATUS_NO_MEMORY
;
1092 status
= cli_full_connection(&cli
, NULL
,
1101 free(machine_account
);
1102 free(machine_password
);
1104 if (!NT_STATUS_IS_OK(status
)) {
1105 status
= cli_full_connection(&cli
, NULL
,
1116 if (!NT_STATUS_IS_OK(status
)) {
1120 status
= get_schannel_session_key(cli
, netbios_domain_name
,
1121 &neg_flags
, &netlogon_pipe
);
1122 if (!NT_STATUS_IS_OK(status
)) {
1123 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_NETWORK_RESPONSE
)) {
1125 return NT_STATUS_OK
;
1128 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1129 "key from server %s for domain %s. Error was %s\n",
1130 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1135 if (!lp_client_schannel()) {
1137 return NT_STATUS_OK
;
1140 status
= cli_rpc_pipe_open_schannel_with_key(
1141 cli
, &ndr_table_netlogon
.syntax_id
, NCACN_NP
,
1142 DCERPC_AUTH_LEVEL_PRIVACY
,
1143 netbios_domain_name
, &netlogon_pipe
->dc
, &pipe_hnd
);
1147 if (!NT_STATUS_IS_OK(status
)) {
1148 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1149 "on netlogon pipe to server %s for domain %s. "
1151 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1155 return NT_STATUS_OK
;
1158 /****************************************************************
1159 ****************************************************************/
1161 static WERROR
libnet_join_post_verify(TALLOC_CTX
*mem_ctx
,
1162 struct libnet_JoinCtx
*r
)
1166 status
= libnet_join_ok(r
->out
.netbios_domain_name
,
1169 if (!NT_STATUS_IS_OK(status
)) {
1170 libnet_join_set_error_string(mem_ctx
, r
,
1171 "failed to verify domain membership after joining: %s",
1172 get_friendly_nt_error_msg(status
));
1173 return WERR_SETUP_NOT_JOINED
;
1179 /****************************************************************
1180 ****************************************************************/
1182 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX
*mem_ctx
,
1183 struct libnet_UnjoinCtx
*r
)
1185 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1189 if (!secrets_delete_domain_sid(lp_workgroup())) {
1196 /****************************************************************
1197 ****************************************************************/
1199 static NTSTATUS
libnet_join_unjoindomain_rpc(TALLOC_CTX
*mem_ctx
,
1200 struct libnet_UnjoinCtx
*r
)
1202 struct cli_state
*cli
= NULL
;
1203 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1204 struct policy_handle sam_pol
, domain_pol
, user_pol
;
1205 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1208 struct lsa_String lsa_acct_name
;
1209 struct samr_Ids user_rids
;
1210 struct samr_Ids name_types
;
1211 union samr_UserInfo
*info
= NULL
;
1213 ZERO_STRUCT(sam_pol
);
1214 ZERO_STRUCT(domain_pol
);
1215 ZERO_STRUCT(user_pol
);
1217 status
= libnet_join_connect_dc_ipc(r
->in
.dc_name
,
1218 r
->in
.admin_account
,
1219 r
->in
.admin_password
,
1222 if (!NT_STATUS_IS_OK(status
)) {
1226 /* Open the domain */
1228 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_samr
.syntax_id
,
1230 if (!NT_STATUS_IS_OK(status
)) {
1231 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1232 nt_errstr(status
)));
1236 status
= rpccli_samr_Connect2(pipe_hnd
, mem_ctx
,
1238 SEC_FLAG_MAXIMUM_ALLOWED
,
1240 if (!NT_STATUS_IS_OK(status
)) {
1244 status
= rpccli_samr_OpenDomain(pipe_hnd
, mem_ctx
,
1246 SEC_FLAG_MAXIMUM_ALLOWED
,
1249 if (!NT_STATUS_IS_OK(status
)) {
1253 /* Create domain user */
1255 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
1256 strlower_m(acct_name
);
1258 init_lsa_String(&lsa_acct_name
, acct_name
);
1260 status
= rpccli_samr_LookupNames(pipe_hnd
, mem_ctx
,
1267 if (!NT_STATUS_IS_OK(status
)) {
1271 if (name_types
.ids
[0] != SID_NAME_USER
) {
1272 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name
,
1273 name_types
.ids
[0]));
1274 status
= NT_STATUS_INVALID_WORKSTATION
;
1278 user_rid
= user_rids
.ids
[0];
1280 /* Open handle on user */
1282 status
= rpccli_samr_OpenUser(pipe_hnd
, mem_ctx
,
1284 SEC_FLAG_MAXIMUM_ALLOWED
,
1287 if (!NT_STATUS_IS_OK(status
)) {
1293 status
= rpccli_samr_QueryUserInfo(pipe_hnd
, mem_ctx
,
1297 if (!NT_STATUS_IS_OK(status
)) {
1298 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1302 /* now disable and setuser info */
1304 info
->info16
.acct_flags
|= ACB_DISABLED
;
1306 status
= rpccli_samr_SetUserInfo(pipe_hnd
, mem_ctx
,
1311 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1315 if (is_valid_policy_hnd(&domain_pol
)) {
1316 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &domain_pol
);
1318 if (is_valid_policy_hnd(&sam_pol
)) {
1319 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &sam_pol
);
1321 TALLOC_FREE(pipe_hnd
);
1331 /****************************************************************
1332 ****************************************************************/
1334 static WERROR
do_join_modify_vals_config(struct libnet_JoinCtx
*r
)
1337 struct smbconf_ctx
*ctx
;
1339 werr
= smbconf_init_reg(r
, &ctx
, NULL
);
1340 if (!W_ERROR_IS_OK(werr
)) {
1344 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1346 werr
= smbconf_set_global_parameter(ctx
, "security", "user");
1347 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1349 werr
= smbconf_set_global_parameter(ctx
, "workgroup",
1352 smbconf_delete_global_parameter(ctx
, "realm");
1356 werr
= smbconf_set_global_parameter(ctx
, "security", "domain");
1357 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1359 werr
= smbconf_set_global_parameter(ctx
, "workgroup",
1360 r
->out
.netbios_domain_name
);
1361 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1363 if (r
->out
.domain_is_ad
) {
1364 werr
= smbconf_set_global_parameter(ctx
, "security", "ads");
1365 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1367 werr
= smbconf_set_global_parameter(ctx
, "realm",
1368 r
->out
.dns_domain_name
);
1369 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1373 smbconf_shutdown(ctx
);
1377 /****************************************************************
1378 ****************************************************************/
1380 static WERROR
do_unjoin_modify_vals_config(struct libnet_UnjoinCtx
*r
)
1382 WERROR werr
= WERR_OK
;
1383 struct smbconf_ctx
*ctx
;
1385 werr
= smbconf_init_reg(r
, &ctx
, NULL
);
1386 if (!W_ERROR_IS_OK(werr
)) {
1390 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1392 werr
= smbconf_set_global_parameter(ctx
, "security", "user");
1393 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1395 werr
= smbconf_delete_global_parameter(ctx
, "workgroup");
1396 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1398 smbconf_delete_global_parameter(ctx
, "realm");
1402 smbconf_shutdown(ctx
);
1406 /****************************************************************
1407 ****************************************************************/
1409 static WERROR
do_JoinConfig(struct libnet_JoinCtx
*r
)
1413 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1414 return r
->out
.result
;
1417 if (!r
->in
.modify_config
) {
1421 werr
= do_join_modify_vals_config(r
);
1422 if (!W_ERROR_IS_OK(werr
)) {
1426 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1428 r
->out
.modified_config
= true;
1429 r
->out
.result
= werr
;
1434 /****************************************************************
1435 ****************************************************************/
1437 static WERROR
libnet_unjoin_config(struct libnet_UnjoinCtx
*r
)
1441 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1442 return r
->out
.result
;
1445 if (!r
->in
.modify_config
) {
1449 werr
= do_unjoin_modify_vals_config(r
);
1450 if (!W_ERROR_IS_OK(werr
)) {
1454 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1456 r
->out
.modified_config
= true;
1457 r
->out
.result
= werr
;
1462 /****************************************************************
1463 ****************************************************************/
1465 static bool libnet_parse_domain_dc(TALLOC_CTX
*mem_ctx
,
1466 const char *domain_str
,
1467 const char **domain_p
,
1470 char *domain
= NULL
;
1472 const char *p
= NULL
;
1474 if (!domain_str
|| !domain_p
|| !dc_p
) {
1478 p
= strchr_m(domain_str
, '\\');
1481 domain
= talloc_strndup(mem_ctx
, domain_str
,
1482 PTR_DIFF(p
, domain_str
));
1483 dc
= talloc_strdup(mem_ctx
, p
+1);
1488 domain
= talloc_strdup(mem_ctx
, domain_str
);
1504 /****************************************************************
1505 ****************************************************************/
1507 static WERROR
libnet_join_pre_processing(TALLOC_CTX
*mem_ctx
,
1508 struct libnet_JoinCtx
*r
)
1510 if (!r
->in
.domain_name
) {
1511 libnet_join_set_error_string(mem_ctx
, r
,
1512 "No domain name defined");
1513 return WERR_INVALID_PARAM
;
1516 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
1519 libnet_join_set_error_string(mem_ctx
, r
,
1520 "Failed to parse domain name");
1521 return WERR_INVALID_PARAM
;
1525 return WERR_SETUP_DOMAIN_CONTROLLER
;
1528 if (!secrets_init()) {
1529 libnet_join_set_error_string(mem_ctx
, r
,
1530 "Unable to open secrets database");
1531 return WERR_CAN_NOT_COMPLETE
;
1537 /****************************************************************
1538 ****************************************************************/
1540 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid
*domain_sid
)
1544 /* Try adding dom admins to builtin\admins. Only log failures. */
1545 status
= create_builtin_administrators(domain_sid
);
1546 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1547 DEBUG(10,("Unable to auto-add domain administrators to "
1548 "BUILTIN\\Administrators during join because "
1549 "winbindd must be running."));
1550 } else if (!NT_STATUS_IS_OK(status
)) {
1551 DEBUG(5, ("Failed to auto-add domain administrators to "
1552 "BUILTIN\\Administrators during join: %s\n",
1553 nt_errstr(status
)));
1556 /* Try adding dom users to builtin\users. Only log failures. */
1557 status
= create_builtin_users(domain_sid
);
1558 if (NT_STATUS_EQUAL(status
, NT_STATUS_PROTOCOL_UNREACHABLE
)) {
1559 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1560 "during join because winbindd must be running."));
1561 } else if (!NT_STATUS_IS_OK(status
)) {
1562 DEBUG(5, ("Failed to auto-add domain administrators to "
1563 "BUILTIN\\Administrators during join: %s\n",
1564 nt_errstr(status
)));
1568 /****************************************************************
1569 ****************************************************************/
1571 static WERROR
libnet_join_post_processing(TALLOC_CTX
*mem_ctx
,
1572 struct libnet_JoinCtx
*r
)
1576 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1577 return r
->out
.result
;
1580 werr
= do_JoinConfig(r
);
1581 if (!W_ERROR_IS_OK(werr
)) {
1585 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1589 saf_join_store(r
->out
.netbios_domain_name
, r
->in
.dc_name
);
1590 if (r
->out
.dns_domain_name
) {
1591 saf_join_store(r
->out
.dns_domain_name
, r
->in
.dc_name
);
1595 if (r
->out
.domain_is_ad
&&
1596 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1597 ADS_STATUS ads_status
;
1599 ads_status
= libnet_join_post_processing_ads(mem_ctx
, r
);
1600 if (!ADS_ERR_OK(ads_status
)) {
1601 return WERR_GENERAL_FAILURE
;
1604 #endif /* WITH_ADS */
1606 libnet_join_add_dom_rids_to_builtins(r
->out
.domain_sid
);
1611 /****************************************************************
1612 ****************************************************************/
1614 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx
*r
)
1616 const char *krb5_cc_env
= NULL
;
1619 ads_destroy(&r
->in
.ads
);
1622 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1623 if (krb5_cc_env
&& StrCaseCmp(krb5_cc_env
, "MEMORY:libnetjoin")) {
1624 unsetenv(KRB5_ENV_CCNAME
);
1630 /****************************************************************
1631 ****************************************************************/
1633 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx
*r
)
1635 const char *krb5_cc_env
= NULL
;
1638 ads_destroy(&r
->in
.ads
);
1641 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1642 if (krb5_cc_env
&& StrCaseCmp(krb5_cc_env
, "MEMORY:libnetjoin")) {
1643 unsetenv(KRB5_ENV_CCNAME
);
1649 /****************************************************************
1650 ****************************************************************/
1652 WERROR
libnet_init_JoinCtx(TALLOC_CTX
*mem_ctx
,
1653 struct libnet_JoinCtx
**r
)
1655 struct libnet_JoinCtx
*ctx
;
1656 const char *krb5_cc_env
= NULL
;
1658 ctx
= talloc_zero(mem_ctx
, struct libnet_JoinCtx
);
1663 talloc_set_destructor(ctx
, libnet_destroy_JoinCtx
);
1665 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1666 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1668 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1669 if (!krb5_cc_env
|| (strlen(krb5_cc_env
) == 0)) {
1670 krb5_cc_env
= talloc_strdup(mem_ctx
, "MEMORY:libnetjoin");
1671 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env
);
1672 setenv(KRB5_ENV_CCNAME
, krb5_cc_env
, 1);
1675 ctx
->in
.secure_channel_type
= SEC_CHAN_WKSTA
;
1682 /****************************************************************
1683 ****************************************************************/
1685 WERROR
libnet_init_UnjoinCtx(TALLOC_CTX
*mem_ctx
,
1686 struct libnet_UnjoinCtx
**r
)
1688 struct libnet_UnjoinCtx
*ctx
;
1689 const char *krb5_cc_env
= NULL
;
1691 ctx
= talloc_zero(mem_ctx
, struct libnet_UnjoinCtx
);
1696 talloc_set_destructor(ctx
, libnet_destroy_UnjoinCtx
);
1698 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1699 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1701 krb5_cc_env
= getenv(KRB5_ENV_CCNAME
);
1702 if (!krb5_cc_env
|| (strlen(krb5_cc_env
) == 0)) {
1703 krb5_cc_env
= talloc_strdup(mem_ctx
, "MEMORY:libnetjoin");
1704 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env
);
1705 setenv(KRB5_ENV_CCNAME
, krb5_cc_env
, 1);
1713 /****************************************************************
1714 ****************************************************************/
1716 static WERROR
libnet_join_check_config(TALLOC_CTX
*mem_ctx
,
1717 struct libnet_JoinCtx
*r
)
1719 bool valid_security
= false;
1720 bool valid_workgroup
= false;
1721 bool valid_realm
= false;
1723 /* check if configuration is already set correctly */
1725 valid_workgroup
= strequal(lp_workgroup(), r
->out
.netbios_domain_name
);
1727 switch (r
->out
.domain_is_ad
) {
1729 valid_security
= (lp_security() == SEC_DOMAIN
);
1730 if (valid_workgroup
&& valid_security
) {
1731 /* nothing to be done */
1736 valid_realm
= strequal(lp_realm(), r
->out
.dns_domain_name
);
1737 switch (lp_security()) {
1740 valid_security
= true;
1743 if (valid_workgroup
&& valid_realm
&& valid_security
) {
1744 /* nothing to be done */
1750 /* check if we are supposed to manipulate configuration */
1752 if (!r
->in
.modify_config
) {
1754 char *wrong_conf
= talloc_strdup(mem_ctx
, "");
1756 if (!valid_workgroup
) {
1757 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1758 "\"workgroup\" set to '%s', should be '%s'",
1759 lp_workgroup(), r
->out
.netbios_domain_name
);
1760 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1764 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1765 "\"realm\" set to '%s', should be '%s'",
1766 lp_realm(), r
->out
.dns_domain_name
);
1767 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1770 if (!valid_security
) {
1771 const char *sec
= NULL
;
1772 switch (lp_security()) {
1773 case SEC_SHARE
: sec
= "share"; break;
1774 case SEC_USER
: sec
= "user"; break;
1775 case SEC_DOMAIN
: sec
= "domain"; break;
1776 case SEC_ADS
: sec
= "ads"; break;
1778 wrong_conf
= talloc_asprintf_append(wrong_conf
,
1779 "\"security\" set to '%s', should be %s",
1780 sec
, r
->out
.domain_is_ad
?
1781 "either 'domain' or 'ads'" : "'domain'");
1782 W_ERROR_HAVE_NO_MEMORY(wrong_conf
);
1785 libnet_join_set_error_string(mem_ctx
, r
,
1786 "Invalid configuration (%s) and configuration modification "
1787 "was not requested", wrong_conf
);
1788 return WERR_CAN_NOT_COMPLETE
;
1791 /* check if we are able to manipulate configuration */
1793 if (!lp_config_backend_is_registry()) {
1794 libnet_join_set_error_string(mem_ctx
, r
,
1795 "Configuration manipulation requested but not "
1796 "supported by backend");
1797 return WERR_NOT_SUPPORTED
;
1803 /****************************************************************
1804 ****************************************************************/
1806 static WERROR
libnet_DomainJoin(TALLOC_CTX
*mem_ctx
,
1807 struct libnet_JoinCtx
*r
)
1811 struct cli_state
*cli
= NULL
;
1813 ADS_STATUS ads_status
;
1814 #endif /* WITH_ADS */
1816 if (!r
->in
.dc_name
) {
1817 struct netr_DsRGetDCNameInfo
*info
;
1819 status
= dsgetdcname(mem_ctx
,
1824 DS_FORCE_REDISCOVERY
|
1825 DS_DIRECTORY_SERVICE_REQUIRED
|
1826 DS_WRITABLE_REQUIRED
|
1829 if (!NT_STATUS_IS_OK(status
)) {
1830 libnet_join_set_error_string(mem_ctx
, r
,
1831 "failed to find DC for domain %s",
1833 get_friendly_nt_error_msg(status
));
1834 return WERR_DCNOTFOUND
;
1837 dc
= strip_hostname(info
->dc_unc
);
1838 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
1839 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
1842 status
= libnet_join_lookup_dc_rpc(mem_ctx
, r
, &cli
);
1843 if (!NT_STATUS_IS_OK(status
)) {
1844 libnet_join_set_error_string(mem_ctx
, r
,
1845 "failed to lookup DC info for domain '%s' over rpc: %s",
1846 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
1847 return ntstatus_to_werror(status
);
1850 werr
= libnet_join_check_config(mem_ctx
, r
);
1851 if (!W_ERROR_IS_OK(werr
)) {
1856 if (r
->out
.domain_is_ad
&& r
->in
.account_ou
&&
1857 !(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
)) {
1859 ads_status
= libnet_join_connect_ads(mem_ctx
, r
);
1860 if (!ADS_ERR_OK(ads_status
)) {
1861 return WERR_DEFAULT_JOIN_REQUIRED
;
1864 ads_status
= libnet_join_precreate_machine_acct(mem_ctx
, r
);
1865 if (!ADS_ERR_OK(ads_status
)) {
1866 libnet_join_set_error_string(mem_ctx
, r
,
1867 "failed to precreate account in ou %s: %s",
1869 ads_errstr(ads_status
));
1870 return WERR_DEFAULT_JOIN_REQUIRED
;
1873 r
->in
.join_flags
&= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
;
1875 #endif /* WITH_ADS */
1877 if ((r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_UNSECURE
) &&
1878 (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED
)) {
1879 status
= libnet_join_joindomain_rpc_unsecure(mem_ctx
, r
, cli
);
1881 status
= libnet_join_joindomain_rpc(mem_ctx
, r
, cli
);
1883 if (!NT_STATUS_IS_OK(status
)) {
1884 libnet_join_set_error_string(mem_ctx
, r
,
1885 "failed to join domain '%s' over rpc: %s",
1886 r
->in
.domain_name
, get_friendly_nt_error_msg(status
));
1887 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
1888 return WERR_SETUP_ALREADY_JOINED
;
1890 werr
= ntstatus_to_werror(status
);
1894 if (!libnet_join_joindomain_store_secrets(mem_ctx
, r
)) {
1895 werr
= WERR_SETUP_NOT_JOINED
;
1909 /****************************************************************
1910 ****************************************************************/
1912 static WERROR
libnet_join_rollback(TALLOC_CTX
*mem_ctx
,
1913 struct libnet_JoinCtx
*r
)
1916 struct libnet_UnjoinCtx
*u
= NULL
;
1918 werr
= libnet_init_UnjoinCtx(mem_ctx
, &u
);
1919 if (!W_ERROR_IS_OK(werr
)) {
1923 u
->in
.debug
= r
->in
.debug
;
1924 u
->in
.dc_name
= r
->in
.dc_name
;
1925 u
->in
.domain_name
= r
->in
.domain_name
;
1926 u
->in
.admin_account
= r
->in
.admin_account
;
1927 u
->in
.admin_password
= r
->in
.admin_password
;
1928 u
->in
.modify_config
= r
->in
.modify_config
;
1929 u
->in
.unjoin_flags
= WKSSVC_JOIN_FLAGS_JOIN_TYPE
|
1930 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
;
1932 werr
= libnet_Unjoin(mem_ctx
, u
);
1938 /****************************************************************
1939 ****************************************************************/
1941 WERROR
libnet_Join(TALLOC_CTX
*mem_ctx
,
1942 struct libnet_JoinCtx
*r
)
1947 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx
, r
);
1950 werr
= libnet_join_pre_processing(mem_ctx
, r
);
1951 if (!W_ERROR_IS_OK(werr
)) {
1955 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1956 werr
= libnet_DomainJoin(mem_ctx
, r
);
1957 if (!W_ERROR_IS_OK(werr
)) {
1962 werr
= libnet_join_post_processing(mem_ctx
, r
);
1963 if (!W_ERROR_IS_OK(werr
)) {
1967 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1968 werr
= libnet_join_post_verify(mem_ctx
, r
);
1969 if (!W_ERROR_IS_OK(werr
)) {
1970 libnet_join_rollback(mem_ctx
, r
);
1975 r
->out
.result
= werr
;
1978 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx
, r
);
1983 /****************************************************************
1984 ****************************************************************/
1986 static WERROR
libnet_DomainUnjoin(TALLOC_CTX
*mem_ctx
,
1987 struct libnet_UnjoinCtx
*r
)
1991 if (!r
->in
.domain_sid
) {
1993 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid
)) {
1994 libnet_unjoin_set_error_string(mem_ctx
, r
,
1995 "Unable to fetch domain sid: are we joined?");
1996 return WERR_SETUP_NOT_JOINED
;
1998 r
->in
.domain_sid
= sid_dup_talloc(mem_ctx
, &sid
);
1999 W_ERROR_HAVE_NO_MEMORY(r
->in
.domain_sid
);
2002 if (!(r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) &&
2003 !r
->in
.delete_machine_account
) {
2004 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2008 if (!r
->in
.dc_name
) {
2009 struct netr_DsRGetDCNameInfo
*info
;
2011 status
= dsgetdcname(mem_ctx
,
2016 DS_DIRECTORY_SERVICE_REQUIRED
|
2017 DS_WRITABLE_REQUIRED
|
2020 if (!NT_STATUS_IS_OK(status
)) {
2021 libnet_unjoin_set_error_string(mem_ctx
, r
,
2022 "failed to find DC for domain %s",
2024 get_friendly_nt_error_msg(status
));
2025 return WERR_DCNOTFOUND
;
2028 dc
= strip_hostname(info
->dc_unc
);
2029 r
->in
.dc_name
= talloc_strdup(mem_ctx
, dc
);
2030 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
2034 /* for net ads leave, try to delete the account. If it works,
2035 no sense in disabling. If it fails, we can still try to
2038 if (r
->in
.delete_machine_account
) {
2039 ADS_STATUS ads_status
;
2040 ads_status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
2041 if (ADS_ERR_OK(ads_status
)) {
2043 r
->out
.dns_domain_name
=
2044 talloc_strdup(mem_ctx
,
2045 r
->in
.ads
->server
.realm
);
2047 libnet_unjoin_remove_machine_acct(mem_ctx
, r
);
2049 if (!ADS_ERR_OK(ads_status
)) {
2050 libnet_unjoin_set_error_string(mem_ctx
, r
,
2051 "failed to remove machine account from AD: %s",
2052 ads_errstr(ads_status
));
2054 r
->out
.deleted_machine_account
= true;
2055 W_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
2056 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2060 #endif /* WITH_ADS */
2062 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2064 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) {
2065 status
= libnet_join_unjoindomain_rpc(mem_ctx
, r
);
2066 if (!NT_STATUS_IS_OK(status
)) {
2067 libnet_unjoin_set_error_string(mem_ctx
, r
,
2068 "failed to disable machine account via rpc: %s",
2069 get_friendly_nt_error_msg(status
));
2070 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
2071 return WERR_SETUP_NOT_JOINED
;
2073 return ntstatus_to_werror(status
);
2076 r
->out
.disabled_machine_account
= true;
2079 /* If disable succeeded or was not requested at all, we
2080 should be getting rid of our end of things */
2082 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
2087 /****************************************************************
2088 ****************************************************************/
2090 static WERROR
libnet_unjoin_pre_processing(TALLOC_CTX
*mem_ctx
,
2091 struct libnet_UnjoinCtx
*r
)
2093 if (!r
->in
.domain_name
) {
2094 libnet_unjoin_set_error_string(mem_ctx
, r
,
2095 "No domain name defined");
2096 return WERR_INVALID_PARAM
;
2099 if (!libnet_parse_domain_dc(mem_ctx
, r
->in
.domain_name
,
2102 libnet_unjoin_set_error_string(mem_ctx
, r
,
2103 "Failed to parse domain name");
2104 return WERR_INVALID_PARAM
;
2108 return WERR_SETUP_DOMAIN_CONTROLLER
;
2111 if (!secrets_init()) {
2112 libnet_unjoin_set_error_string(mem_ctx
, r
,
2113 "Unable to open secrets database");
2114 return WERR_CAN_NOT_COMPLETE
;
2120 /****************************************************************
2121 ****************************************************************/
2123 static WERROR
libnet_unjoin_post_processing(TALLOC_CTX
*mem_ctx
,
2124 struct libnet_UnjoinCtx
*r
)
2126 saf_delete(r
->out
.netbios_domain_name
);
2127 saf_delete(r
->out
.dns_domain_name
);
2129 return libnet_unjoin_config(r
);
2132 /****************************************************************
2133 ****************************************************************/
2135 WERROR
libnet_Unjoin(TALLOC_CTX
*mem_ctx
,
2136 struct libnet_UnjoinCtx
*r
)
2141 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx
, r
);
2144 werr
= libnet_unjoin_pre_processing(mem_ctx
, r
);
2145 if (!W_ERROR_IS_OK(werr
)) {
2149 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
2150 werr
= libnet_DomainUnjoin(mem_ctx
, r
);
2151 if (!W_ERROR_IS_OK(werr
)) {
2152 libnet_unjoin_config(r
);
2157 werr
= libnet_unjoin_post_processing(mem_ctx
, r
);
2158 if (!W_ERROR_IS_OK(werr
)) {
2163 r
->out
.result
= werr
;
2166 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx
, r
);