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"
24 /****************************************************************
25 ****************************************************************/
27 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
30 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
31 DEBUG(1,("libnet_Join:\n%s", str)); \
35 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
36 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
37 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
38 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
40 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
43 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
44 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
48 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
49 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
50 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
51 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
53 #define W_ERROR_NOT_OK_GOTO_DONE(x) do { \
54 if (!W_ERROR_IS_OK(x)) {\
59 /****************************************************************
60 ****************************************************************/
62 static void libnet_join_set_error_string(TALLOC_CTX
*mem_ctx
,
63 struct libnet_JoinCtx
*r
,
64 const char *format
, ...)
68 if (r
->out
.error_string
) {
72 va_start(args
, format
);
73 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
77 /****************************************************************
78 ****************************************************************/
80 static void libnet_unjoin_set_error_string(TALLOC_CTX
*mem_ctx
,
81 struct libnet_UnjoinCtx
*r
,
82 const char *format
, ...)
86 if (r
->out
.error_string
) {
90 va_start(args
, format
);
91 r
->out
.error_string
= talloc_vasprintf(mem_ctx
, format
, args
);
97 /****************************************************************
98 ****************************************************************/
100 static ADS_STATUS
libnet_connect_ads(const char *dns_domain_name
,
101 const char *netbios_domain_name
,
103 const char *user_name
,
104 const char *password
,
108 ADS_STRUCT
*my_ads
= NULL
;
110 my_ads
= ads_init(dns_domain_name
,
114 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
118 SAFE_FREE(my_ads
->auth
.user_name
);
119 my_ads
->auth
.user_name
= SMB_STRDUP(user_name
);
123 SAFE_FREE(my_ads
->auth
.password
);
124 my_ads
->auth
.password
= SMB_STRDUP(password
);
127 status
= ads_connect(my_ads
);
128 if (!ADS_ERR_OK(status
)) {
129 ads_destroy(&my_ads
);
137 /****************************************************************
138 ****************************************************************/
140 static ADS_STATUS
libnet_join_connect_ads(TALLOC_CTX
*mem_ctx
,
141 struct libnet_JoinCtx
*r
)
145 status
= libnet_connect_ads(r
->in
.domain_name
,
149 r
->in
.admin_password
,
151 if (!ADS_ERR_OK(status
)) {
152 libnet_join_set_error_string(mem_ctx
, r
,
153 "failed to connect to AD: %s",
158 if (!r
->out
.netbios_domain_name
) {
159 r
->out
.netbios_domain_name
= talloc_strdup(mem_ctx
,
160 r
->in
.ads
->server
.workgroup
);
161 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.netbios_domain_name
);
164 if (!r
->out
.dns_domain_name
) {
165 r
->out
.dns_domain_name
= talloc_strdup(mem_ctx
,
166 r
->in
.ads
->config
.realm
);
167 ADS_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
170 r
->out
.domain_is_ad
= true;
175 /****************************************************************
176 ****************************************************************/
178 static ADS_STATUS
libnet_unjoin_connect_ads(TALLOC_CTX
*mem_ctx
,
179 struct libnet_UnjoinCtx
*r
)
183 status
= libnet_connect_ads(r
->in
.domain_name
,
187 r
->in
.admin_password
,
189 if (!ADS_ERR_OK(status
)) {
190 libnet_unjoin_set_error_string(mem_ctx
, r
,
191 "failed to connect to AD: %s",
198 /****************************************************************
199 join a domain using ADS (LDAP mods)
200 ****************************************************************/
202 static ADS_STATUS
libnet_join_precreate_machine_acct(TALLOC_CTX
*mem_ctx
,
203 struct libnet_JoinCtx
*r
)
206 LDAPMessage
*res
= NULL
;
207 const char *attrs
[] = { "dn", NULL
};
210 status
= ads_search_dn(r
->in
.ads
, &res
, r
->in
.account_ou
, attrs
);
211 if (!ADS_ERR_OK(status
)) {
215 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
216 ads_msgfree(r
->in
.ads
, res
);
217 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT
);
220 ads_msgfree(r
->in
.ads
, res
);
222 /* Attempt to create the machine account and bail if this fails.
223 Assume that the admin wants exactly what they requested */
225 status
= ads_create_machine_acct(r
->in
.ads
,
229 if (ADS_ERR_OK(status
)) {
230 DEBUG(1,("machine account creation created\n"));
232 } else if ((status
.error_type
== ENUM_ADS_ERROR_LDAP
) &&
233 (status
.err
.rc
== LDAP_ALREADY_EXISTS
)) {
234 status
= ADS_SUCCESS
;
237 if (!ADS_ERR_OK(status
)) {
238 DEBUG(1,("machine account creation failed\n"));
242 status
= ads_move_machine_acct(r
->in
.ads
,
246 if (!ADS_ERR_OK(status
)) {
247 DEBUG(1,("failure to locate/move pre-existing "
248 "machine account\n"));
252 DEBUG(1,("The machine account %s the specified OU.\n",
253 moved
? "was moved into" : "already exists in"));
258 /****************************************************************
259 ****************************************************************/
261 static ADS_STATUS
libnet_unjoin_remove_machine_acct(TALLOC_CTX
*mem_ctx
,
262 struct libnet_UnjoinCtx
*r
)
267 status
= libnet_unjoin_connect_ads(mem_ctx
, r
);
268 if (!ADS_ERR_OK(status
)) {
273 status
= ads_leave_realm(r
->in
.ads
, r
->in
.machine_name
);
274 if (!ADS_ERR_OK(status
)) {
275 libnet_unjoin_set_error_string(mem_ctx
, r
,
276 "failed to leave realm: %s",
284 /****************************************************************
285 ****************************************************************/
287 static ADS_STATUS
libnet_join_find_machine_acct(TALLOC_CTX
*mem_ctx
,
288 struct libnet_JoinCtx
*r
)
291 LDAPMessage
*res
= NULL
;
294 if (!r
->in
.machine_name
) {
295 return ADS_ERROR(LDAP_NO_MEMORY
);
298 status
= ads_find_machine_acct(r
->in
.ads
,
301 if (!ADS_ERR_OK(status
)) {
305 if (ads_count_replies(r
->in
.ads
, res
) != 1) {
306 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
310 dn
= ads_get_dn(r
->in
.ads
, res
);
312 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
316 r
->out
.dn
= talloc_strdup(mem_ctx
, dn
);
318 status
= ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
323 ads_msgfree(r
->in
.ads
, res
);
324 ads_memfree(r
->in
.ads
, dn
);
329 /****************************************************************
330 Set a machines dNSHostName and servicePrincipalName attributes
331 ****************************************************************/
333 static ADS_STATUS
libnet_join_set_machine_spn(TALLOC_CTX
*mem_ctx
,
334 struct libnet_JoinCtx
*r
)
339 const char *spn_array
[3] = {NULL
, NULL
, NULL
};
344 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
345 if (!ADS_ERR_OK(status
)) {
349 /* Windows only creates HOST/shortname & HOST/fqdn. */
351 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", r
->in
.machine_name
);
353 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
358 if (name_to_fqdn(my_fqdn
, r
->in
.machine_name
) &&
359 !strequal(my_fqdn
, r
->in
.machine_name
)) {
362 spn
= talloc_asprintf(mem_ctx
, "HOST/%s", my_fqdn
);
364 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
369 mods
= ads_init_mods(mem_ctx
);
371 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
374 /* fields of primary importance */
376 status
= ads_mod_str(mem_ctx
, &mods
, "dNSHostName", my_fqdn
);
377 if (!ADS_ERR_OK(status
)) {
378 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
381 status
= ads_mod_strlist(mem_ctx
, &mods
, "servicePrincipalName",
383 if (!ADS_ERR_OK(status
)) {
384 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
387 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
390 /****************************************************************
391 ****************************************************************/
393 static ADS_STATUS
libnet_join_set_machine_upn(TALLOC_CTX
*mem_ctx
,
394 struct libnet_JoinCtx
*r
)
399 if (!r
->in
.create_upn
) {
405 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
406 if (!ADS_ERR_OK(status
)) {
411 r
->in
.upn
= talloc_asprintf(mem_ctx
,
414 r
->out
.dns_domain_name
);
416 return ADS_ERROR(LDAP_NO_MEMORY
);
420 /* now do the mods */
422 mods
= ads_init_mods(mem_ctx
);
424 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
427 /* fields of primary importance */
429 status
= ads_mod_str(mem_ctx
, &mods
, "userPrincipalName", r
->in
.upn
);
430 if (!ADS_ERR_OK(status
)) {
431 return ADS_ERROR_LDAP(LDAP_NO_MEMORY
);
434 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
438 /****************************************************************
439 ****************************************************************/
441 static ADS_STATUS
libnet_join_set_os_attributes(TALLOC_CTX
*mem_ctx
,
442 struct libnet_JoinCtx
*r
)
448 if (!r
->in
.os_name
|| !r
->in
.os_version
) {
454 status
= libnet_join_find_machine_acct(mem_ctx
, r
);
455 if (!ADS_ERR_OK(status
)) {
459 /* now do the mods */
461 mods
= ads_init_mods(mem_ctx
);
463 return ADS_ERROR(LDAP_NO_MEMORY
);
466 os_sp
= talloc_asprintf(mem_ctx
, "Samba %s", SAMBA_VERSION_STRING
);
468 return ADS_ERROR(LDAP_NO_MEMORY
);
471 /* fields of primary importance */
473 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystem",
475 if (!ADS_ERR_OK(status
)) {
479 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemVersion",
481 if (!ADS_ERR_OK(status
)) {
485 status
= ads_mod_str(mem_ctx
, &mods
, "operatingSystemServicePack",
487 if (!ADS_ERR_OK(status
)) {
491 return ads_gen_mod(r
->in
.ads
, r
->out
.dn
, mods
);
494 /****************************************************************
495 ****************************************************************/
497 static bool libnet_join_create_keytab(TALLOC_CTX
*mem_ctx
,
498 struct libnet_JoinCtx
*r
)
500 if (!lp_use_kerberos_keytab()) {
504 if (!ads_keytab_create_default(r
->in
.ads
)) {
511 /****************************************************************
512 ****************************************************************/
514 static bool libnet_join_derive_salting_principal(TALLOC_CTX
*mem_ctx
,
515 struct libnet_JoinCtx
*r
)
517 uint32_t domain_func
;
519 const char *salt
= NULL
;
520 char *std_salt
= NULL
;
522 status
= ads_domain_func_level(r
->in
.ads
, &domain_func
);
523 if (!ADS_ERR_OK(status
)) {
524 libnet_join_set_error_string(mem_ctx
, r
,
525 "failed to determine domain functional level: %s",
530 /* go ahead and setup the default salt */
532 std_salt
= kerberos_standard_des_salt();
534 libnet_join_set_error_string(mem_ctx
, r
,
535 "failed to obtain standard DES salt");
539 salt
= talloc_strdup(mem_ctx
, std_salt
);
546 /* if it's a Windows functional domain, we have to look for the UPN */
548 if (domain_func
== DS_DOMAIN_FUNCTION_2000
) {
551 upn
= ads_get_upn(r
->in
.ads
, mem_ctx
,
554 salt
= talloc_strdup(mem_ctx
, upn
);
561 return kerberos_secrets_store_des_salt(salt
);
564 /****************************************************************
565 ****************************************************************/
567 static ADS_STATUS
libnet_join_post_processing_ads(TALLOC_CTX
*mem_ctx
,
568 struct libnet_JoinCtx
*r
)
573 status
= libnet_join_connect_ads(mem_ctx
, r
);
574 if (!ADS_ERR_OK(status
)) {
579 status
= libnet_join_set_machine_spn(mem_ctx
, r
);
580 if (!ADS_ERR_OK(status
)) {
581 libnet_join_set_error_string(mem_ctx
, r
,
582 "failed to set machine spn: %s",
587 status
= libnet_join_set_os_attributes(mem_ctx
, r
);
588 if (!ADS_ERR_OK(status
)) {
589 libnet_join_set_error_string(mem_ctx
, r
,
590 "failed to set machine os attributes: %s",
595 status
= libnet_join_set_machine_upn(mem_ctx
, r
);
596 if (!ADS_ERR_OK(status
)) {
597 libnet_join_set_error_string(mem_ctx
, r
,
598 "failed to set machine upn: %s",
603 if (!libnet_join_derive_salting_principal(mem_ctx
, r
)) {
604 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
607 if (!libnet_join_create_keytab(mem_ctx
, r
)) {
608 libnet_join_set_error_string(mem_ctx
, r
,
609 "failed to create kerberos keytab");
610 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
615 #endif /* WITH_ADS */
617 /****************************************************************
618 Store the machine password and domain SID
619 ****************************************************************/
621 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX
*mem_ctx
,
622 struct libnet_JoinCtx
*r
)
624 if (!secrets_store_domain_sid(r
->out
.netbios_domain_name
,
627 DEBUG(1,("Failed to save domain sid\n"));
631 if (!secrets_store_machine_password(r
->in
.machine_password
,
632 r
->out
.netbios_domain_name
,
635 DEBUG(1,("Failed to save machine password\n"));
642 /****************************************************************
644 ****************************************************************/
646 static NTSTATUS
libnet_join_joindomain_rpc(TALLOC_CTX
*mem_ctx
,
647 struct libnet_JoinCtx
*r
)
649 struct cli_state
*cli
= NULL
;
650 struct rpc_pipe_client
*pipe_hnd
= NULL
;
651 POLICY_HND sam_pol
, domain_pol
, user_pol
, lsa_pol
;
652 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
654 struct lsa_String lsa_acct_name
;
656 uint32_t acct_flags
= ACB_WSTRUST
;
658 struct MD5Context md5ctx
;
660 DATA_BLOB digested_session_key
;
661 uchar md4_trust_password
[16];
662 union lsa_PolicyInformation
*info
= NULL
;
663 struct samr_Ids user_rids
;
664 struct samr_Ids name_types
;
665 union samr_UserInfo user_info
;
667 if (!r
->in
.machine_password
) {
668 r
->in
.machine_password
= talloc_strdup(mem_ctx
, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH
));
669 NT_STATUS_HAVE_NO_MEMORY(r
->in
.machine_password
);
672 status
= cli_full_connection(&cli
, NULL
,
678 r
->in
.admin_password
,
682 if (!NT_STATUS_IS_OK(status
)) {
686 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_LSARPC
, &status
);
688 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
693 status
= rpccli_lsa_open_policy(pipe_hnd
, mem_ctx
, true,
694 SEC_RIGHTS_MAXIMUM_ALLOWED
, &lsa_pol
);
695 if (!NT_STATUS_IS_OK(status
)) {
699 status
= rpccli_lsa_QueryInfoPolicy2(pipe_hnd
, mem_ctx
,
703 if (NT_STATUS_IS_OK(status
)) {
704 r
->out
.domain_is_ad
= true;
705 r
->out
.netbios_domain_name
= info
->dns
.name
.string
;
706 r
->out
.dns_domain_name
= info
->dns
.dns_domain
.string
;
707 r
->out
.domain_sid
= info
->dns
.sid
;
710 if (!NT_STATUS_IS_OK(status
)) {
711 status
= rpccli_lsa_QueryInfoPolicy(pipe_hnd
, mem_ctx
,
713 LSA_POLICY_INFO_ACCOUNT_DOMAIN
,
715 if (!NT_STATUS_IS_OK(status
)) {
719 r
->out
.netbios_domain_name
= info
->account_domain
.name
.string
;
720 r
->out
.domain_sid
= info
->account_domain
.sid
;
723 rpccli_lsa_Close(pipe_hnd
, mem_ctx
, &lsa_pol
);
724 cli_rpc_pipe_close(pipe_hnd
);
726 /* Open the domain */
728 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_SAMR
, &status
);
730 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
735 status
= rpccli_samr_Connect2(pipe_hnd
, mem_ctx
,
736 pipe_hnd
->cli
->desthost
,
737 SEC_RIGHTS_MAXIMUM_ALLOWED
,
739 if (!NT_STATUS_IS_OK(status
)) {
743 status
= rpccli_samr_OpenDomain(pipe_hnd
, mem_ctx
,
745 SEC_RIGHTS_MAXIMUM_ALLOWED
,
748 if (!NT_STATUS_IS_OK(status
)) {
752 /* Create domain user */
754 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
755 strlower_m(acct_name
);
757 init_lsa_String(&lsa_acct_name
, acct_name
);
759 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
) {
760 uint32_t access_desired
=
761 SEC_GENERIC_READ
| SEC_GENERIC_WRITE
| SEC_GENERIC_EXECUTE
|
762 SEC_STD_WRITE_DAC
| SEC_STD_DELETE
|
763 SAMR_USER_ACCESS_SET_PASSWORD
|
764 SAMR_USER_ACCESS_GET_ATTRIBUTES
|
765 SAMR_USER_ACCESS_SET_ATTRIBUTES
;
766 uint32_t access_granted
= 0;
768 /* Don't try to set any acct_flags flags other than ACB_WSTRUST */
770 DEBUG(10,("Creating account with desired access mask: %d\n",
773 status
= rpccli_samr_CreateUser2(pipe_hnd
, mem_ctx
,
781 if (!NT_STATUS_IS_OK(status
) &&
782 !NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
784 DEBUG(10,("Creation of workstation account failed: %s\n",
787 /* If NT_STATUS_ACCESS_DENIED then we have a valid
788 username/password combo but the user does not have
789 administrator access. */
791 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
792 libnet_join_set_error_string(mem_ctx
, r
,
793 "User specified does not have "
794 "administrator privileges");
800 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
801 if (!(r
->in
.join_flags
&
802 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED
)) {
807 /* We *must* do this.... don't ask... */
809 if (NT_STATUS_IS_OK(status
)) {
810 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
814 status
= rpccli_samr_LookupNames(pipe_hnd
, mem_ctx
,
820 if (!NT_STATUS_IS_OK(status
)) {
824 if (name_types
.ids
[0] != SID_NAME_USER
) {
825 DEBUG(0,("%s is not a user account (type=%d)\n",
826 acct_name
, name_types
.ids
[0]));
827 status
= NT_STATUS_INVALID_WORKSTATION
;
831 user_rid
= user_rids
.ids
[0];
833 /* Open handle on user */
835 status
= rpccli_samr_OpenUser(pipe_hnd
, mem_ctx
,
837 SEC_RIGHTS_MAXIMUM_ALLOWED
,
840 if (!NT_STATUS_IS_OK(status
)) {
844 /* Create a random machine account password and generate the hash */
846 E_md4hash(r
->in
.machine_password
, md4_trust_password
);
847 encode_pw_buffer(pwbuf
, r
->in
.machine_password
, STR_UNICODE
);
849 generate_random_buffer((uint8_t*)md5buffer
, sizeof(md5buffer
));
850 digested_session_key
= data_blob_talloc(mem_ctx
, 0, 16);
853 MD5Update(&md5ctx
, md5buffer
, sizeof(md5buffer
));
854 MD5Update(&md5ctx
, cli
->user_session_key
.data
,
855 cli
->user_session_key
.length
);
856 MD5Final(digested_session_key
.data
, &md5ctx
);
858 SamOEMhashBlob(pwbuf
, sizeof(pwbuf
), &digested_session_key
);
859 memcpy(&pwbuf
[516], md5buffer
, sizeof(md5buffer
));
861 /* Fill in the additional account flags now */
863 acct_flags
|= ACB_PWNOEXP
;
864 if (r
->out
.domain_is_ad
) {
865 #if !defined(ENCTYPE_ARCFOUR_HMAC)
866 acct_flags
|= ACB_USE_DES_KEY_ONLY
;
871 /* Set password and account flags on machine account */
873 ZERO_STRUCT(user_info
.info25
);
875 user_info
.info25
.info
.fields_present
= ACCT_NT_PWD_SET
|
877 SAMR_FIELD_ACCT_FLAGS
;
879 user_info
.info25
.info
.acct_flags
= acct_flags
;
880 memcpy(&user_info
.info25
.password
.data
, pwbuf
, sizeof(pwbuf
));
882 status
= rpccli_samr_SetUserInfo(pipe_hnd
, mem_ctx
,
887 if (NT_STATUS_EQUAL(status
, NT_STATUS(DCERPC_FAULT_INVALID_TAG
))) {
891 encode_pw_buffer(pwbuf2
, r
->in
.machine_password
, STR_UNICODE
);
893 /* retry with level 24 */
894 init_samr_user_info24(&user_info
.info24
, pwbuf2
, 24);
896 SamOEMhashBlob(user_info
.info24
.password
.data
, 516,
897 &cli
->user_session_key
);
899 status
= rpccli_samr_SetUserInfo2(pipe_hnd
, mem_ctx
,
905 if (!NT_STATUS_IS_OK(status
)) {
906 libnet_join_set_error_string(mem_ctx
, r
,
907 "Failed to set password for machine account (%s)\n",
912 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
913 cli_rpc_pipe_close(pipe_hnd
);
915 status
= NT_STATUS_OK
;
924 /****************************************************************
925 ****************************************************************/
927 NTSTATUS
libnet_join_ok(const char *netbios_domain_name
,
928 const char *machine_name
,
931 uint32_t neg_flags
= NETLOGON_NEG_SELECT_AUTH2_FLAGS
|
932 NETLOGON_NEG_SCHANNEL
;
933 struct cli_state
*cli
= NULL
;
934 struct rpc_pipe_client
*pipe_hnd
= NULL
;
935 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
937 char *machine_password
= NULL
;
938 char *machine_account
= NULL
;
941 return NT_STATUS_INVALID_PARAMETER
;
944 if (!secrets_init()) {
945 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
948 machine_password
= secrets_fetch_machine_password(netbios_domain_name
,
950 if (!machine_password
) {
951 return NT_STATUS_NO_TRUST_LSA_SECRET
;
954 asprintf(&machine_account
, "%s$", machine_name
);
955 if (!machine_account
) {
956 SAFE_FREE(machine_password
);
957 return NT_STATUS_NO_MEMORY
;
960 status
= cli_full_connection(&cli
, NULL
,
969 free(machine_account
);
970 free(machine_password
);
972 if (!NT_STATUS_IS_OK(status
)) {
973 status
= cli_full_connection(&cli
, NULL
,
984 if (!NT_STATUS_IS_OK(status
)) {
988 netlogon_pipe
= get_schannel_session_key(cli
,
990 &neg_flags
, &status
);
991 if (!netlogon_pipe
) {
992 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_NETWORK_RESPONSE
)) {
997 DEBUG(0,("libnet_join_ok: failed to get schannel session "
998 "key from server %s for domain %s. Error was %s\n",
999 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1004 if (!lp_client_schannel()) {
1006 return NT_STATUS_OK
;
1009 pipe_hnd
= cli_rpc_pipe_open_schannel_with_key(cli
, PI_NETLOGON
,
1010 PIPE_AUTH_LEVEL_PRIVACY
,
1011 netbios_domain_name
,
1018 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1019 "on netlogon pipe to server %s for domain %s. "
1021 cli
->desthost
, netbios_domain_name
, nt_errstr(status
)));
1025 return NT_STATUS_OK
;
1028 /****************************************************************
1029 ****************************************************************/
1031 static WERROR
libnet_join_post_verify(TALLOC_CTX
*mem_ctx
,
1032 struct libnet_JoinCtx
*r
)
1036 status
= libnet_join_ok(r
->out
.netbios_domain_name
,
1039 if (!NT_STATUS_IS_OK(status
)) {
1040 libnet_join_set_error_string(mem_ctx
, r
,
1041 "failed to verify domain membership after joining: %s",
1042 get_friendly_nt_error_msg(status
));
1043 return WERR_SETUP_NOT_JOINED
;
1049 /****************************************************************
1050 ****************************************************************/
1052 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX
*mem_ctx
,
1053 struct libnet_UnjoinCtx
*r
)
1055 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1059 if (!secrets_delete_domain_sid(lp_workgroup())) {
1066 /****************************************************************
1067 ****************************************************************/
1069 static NTSTATUS
libnet_join_unjoindomain_rpc(TALLOC_CTX
*mem_ctx
,
1070 struct libnet_UnjoinCtx
*r
)
1072 struct cli_state
*cli
= NULL
;
1073 struct rpc_pipe_client
*pipe_hnd
= NULL
;
1074 POLICY_HND sam_pol
, domain_pol
, user_pol
;
1075 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1078 struct lsa_String lsa_acct_name
;
1079 struct samr_Ids user_rids
;
1080 struct samr_Ids name_types
;
1081 union samr_UserInfo
*info
= NULL
;
1083 status
= cli_full_connection(&cli
, NULL
,
1087 r
->in
.admin_account
,
1089 r
->in
.admin_password
,
1090 0, Undefined
, NULL
);
1092 if (!NT_STATUS_IS_OK(status
)) {
1096 /* Open the domain */
1098 pipe_hnd
= cli_rpc_pipe_open_noauth(cli
, PI_SAMR
, &status
);
1100 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1101 nt_errstr(status
)));
1105 status
= rpccli_samr_Connect2(pipe_hnd
, mem_ctx
,
1106 pipe_hnd
->cli
->desthost
,
1107 SEC_RIGHTS_MAXIMUM_ALLOWED
,
1109 if (!NT_STATUS_IS_OK(status
)) {
1113 status
= rpccli_samr_OpenDomain(pipe_hnd
, mem_ctx
,
1115 SEC_RIGHTS_MAXIMUM_ALLOWED
,
1118 if (!NT_STATUS_IS_OK(status
)) {
1122 /* Create domain user */
1124 acct_name
= talloc_asprintf(mem_ctx
, "%s$", r
->in
.machine_name
);
1125 strlower_m(acct_name
);
1127 init_lsa_String(&lsa_acct_name
, acct_name
);
1129 status
= rpccli_samr_LookupNames(pipe_hnd
, mem_ctx
,
1136 if (!NT_STATUS_IS_OK(status
)) {
1140 if (name_types
.ids
[0] != SID_NAME_USER
) {
1141 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name
,
1142 name_types
.ids
[0]));
1143 status
= NT_STATUS_INVALID_WORKSTATION
;
1147 user_rid
= user_rids
.ids
[0];
1149 /* Open handle on user */
1151 status
= rpccli_samr_OpenUser(pipe_hnd
, mem_ctx
,
1153 SEC_RIGHTS_MAXIMUM_ALLOWED
,
1156 if (!NT_STATUS_IS_OK(status
)) {
1162 status
= rpccli_samr_QueryUserInfo(pipe_hnd
, mem_ctx
,
1166 if (!NT_STATUS_IS_OK(status
)) {
1167 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1171 /* now disable and setuser info */
1173 info
->info16
.acct_flags
|= ACB_DISABLED
;
1175 status
= rpccli_samr_SetUserInfo(pipe_hnd
, mem_ctx
,
1180 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &user_pol
);
1184 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &domain_pol
);
1185 rpccli_samr_Close(pipe_hnd
, mem_ctx
, &sam_pol
);
1186 cli_rpc_pipe_close(pipe_hnd
);
1196 /****************************************************************
1197 ****************************************************************/
1199 static WERROR
do_join_modify_vals_config(struct libnet_JoinCtx
*r
)
1202 struct libnet_conf_ctx
*ctx
;
1204 werr
= libnet_conf_open(r
, &ctx
);
1205 if (!W_ERROR_IS_OK(werr
)) {
1209 if (!(r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
)) {
1211 werr
= libnet_conf_set_global_parameter(ctx
, "security", "user");
1212 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1214 werr
= libnet_conf_set_global_parameter(ctx
, "workgroup",
1219 werr
= libnet_conf_set_global_parameter(ctx
, "security", "domain");
1220 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1222 werr
= libnet_conf_set_global_parameter(ctx
, "workgroup",
1223 r
->out
.netbios_domain_name
);
1224 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1226 if (r
->out
.domain_is_ad
) {
1227 werr
= libnet_conf_set_global_parameter(ctx
, "security", "ads");
1228 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1230 werr
= libnet_conf_set_global_parameter(ctx
, "realm",
1231 r
->out
.dns_domain_name
);
1232 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1236 libnet_conf_close(ctx
);
1240 /****************************************************************
1241 ****************************************************************/
1243 static WERROR
do_unjoin_modify_vals_config(struct libnet_UnjoinCtx
*r
)
1245 WERROR werr
= WERR_OK
;
1246 struct libnet_conf_ctx
*ctx
;
1248 werr
= libnet_conf_open(r
, &ctx
);
1249 if (!W_ERROR_IS_OK(werr
)) {
1253 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1255 werr
= libnet_conf_set_global_parameter(ctx
, "security", "user");
1256 W_ERROR_NOT_OK_GOTO_DONE(werr
);
1257 libnet_conf_delete_global_parameter(ctx
, "realm");
1261 libnet_conf_close(ctx
);
1265 /****************************************************************
1266 ****************************************************************/
1268 static WERROR
do_JoinConfig(struct libnet_JoinCtx
*r
)
1272 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1273 return r
->out
.result
;
1276 if (!r
->in
.modify_config
) {
1280 werr
= do_join_modify_vals_config(r
);
1281 if (!W_ERROR_IS_OK(werr
)) {
1285 r
->out
.modified_config
= true;
1286 r
->out
.result
= werr
;
1291 /****************************************************************
1292 ****************************************************************/
1294 static WERROR
libnet_unjoin_config(struct libnet_UnjoinCtx
*r
)
1298 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1299 return r
->out
.result
;
1302 if (!r
->in
.modify_config
) {
1306 werr
= do_unjoin_modify_vals_config(r
);
1307 if (!W_ERROR_IS_OK(werr
)) {
1311 r
->out
.modified_config
= true;
1312 r
->out
.result
= werr
;
1317 /****************************************************************
1318 ****************************************************************/
1320 static WERROR
libnet_join_pre_processing(TALLOC_CTX
*mem_ctx
,
1321 struct libnet_JoinCtx
*r
)
1323 if (!r
->in
.domain_name
) {
1324 libnet_join_set_error_string(mem_ctx
, r
,
1325 "No domain name defined");
1326 return WERR_INVALID_PARAM
;
1329 if (r
->in
.modify_config
&& !lp_config_backend_is_registry()) {
1330 libnet_join_set_error_string(mem_ctx
, r
,
1331 "Configuration manipulation requested but not "
1332 "supported by backend");
1333 return WERR_NOT_SUPPORTED
;
1337 return WERR_SETUP_DOMAIN_CONTROLLER
;
1340 if (!secrets_init()) {
1341 libnet_join_set_error_string(mem_ctx
, r
,
1342 "Unable to open secrets database");
1343 return WERR_CAN_NOT_COMPLETE
;
1349 /****************************************************************
1350 ****************************************************************/
1352 static WERROR
libnet_join_post_processing(TALLOC_CTX
*mem_ctx
,
1353 struct libnet_JoinCtx
*r
)
1357 if (!W_ERROR_IS_OK(r
->out
.result
)) {
1358 return r
->out
.result
;
1361 werr
= do_JoinConfig(r
);
1362 if (!W_ERROR_IS_OK(werr
)) {
1366 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1367 saf_store(r
->in
.domain_name
, r
->in
.dc_name
);
1373 /****************************************************************
1374 ****************************************************************/
1376 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx
*r
)
1379 ads_destroy(&r
->in
.ads
);
1385 /****************************************************************
1386 ****************************************************************/
1388 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx
*r
)
1391 ads_destroy(&r
->in
.ads
);
1397 /****************************************************************
1398 ****************************************************************/
1400 WERROR
libnet_init_JoinCtx(TALLOC_CTX
*mem_ctx
,
1401 struct libnet_JoinCtx
**r
)
1403 struct libnet_JoinCtx
*ctx
;
1405 ctx
= talloc_zero(mem_ctx
, struct libnet_JoinCtx
);
1410 talloc_set_destructor(ctx
, libnet_destroy_JoinCtx
);
1412 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1413 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1420 /****************************************************************
1421 ****************************************************************/
1423 WERROR
libnet_init_UnjoinCtx(TALLOC_CTX
*mem_ctx
,
1424 struct libnet_UnjoinCtx
**r
)
1426 struct libnet_UnjoinCtx
*ctx
;
1428 ctx
= talloc_zero(mem_ctx
, struct libnet_UnjoinCtx
);
1433 talloc_set_destructor(ctx
, libnet_destroy_UnjoinCtx
);
1435 ctx
->in
.machine_name
= talloc_strdup(mem_ctx
, global_myname());
1436 W_ERROR_HAVE_NO_MEMORY(ctx
->in
.machine_name
);
1443 /****************************************************************
1444 ****************************************************************/
1446 static WERROR
libnet_DomainJoin(TALLOC_CTX
*mem_ctx
,
1447 struct libnet_JoinCtx
*r
)
1451 ADS_STATUS ads_status
;
1452 #endif /* WITH_ADS */
1454 if (!r
->in
.dc_name
) {
1455 struct netr_DsRGetDCNameInfo
*info
;
1456 status
= dsgetdcname(mem_ctx
,
1460 DS_DIRECTORY_SERVICE_REQUIRED
|
1461 DS_WRITABLE_REQUIRED
|
1464 if (!NT_STATUS_IS_OK(status
)) {
1465 libnet_join_set_error_string(mem_ctx
, r
,
1466 "failed to find DC for domain %s",
1468 get_friendly_nt_error_msg(status
));
1469 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1472 r
->in
.dc_name
= talloc_strdup(mem_ctx
,
1474 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
1478 if (r
->in
.account_ou
) {
1480 ads_status
= libnet_join_connect_ads(mem_ctx
, r
);
1481 if (!ADS_ERR_OK(ads_status
)) {
1482 return WERR_DEFAULT_JOIN_REQUIRED
;
1485 ads_status
= libnet_join_precreate_machine_acct(mem_ctx
, r
);
1486 if (!ADS_ERR_OK(ads_status
)) {
1487 libnet_join_set_error_string(mem_ctx
, r
,
1488 "failed to precreate account in ou %s: %s",
1490 ads_errstr(ads_status
));
1491 return WERR_DEFAULT_JOIN_REQUIRED
;
1494 r
->in
.join_flags
&= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE
;
1496 #endif /* WITH_ADS */
1498 status
= libnet_join_joindomain_rpc(mem_ctx
, r
);
1499 if (!NT_STATUS_IS_OK(status
)) {
1500 libnet_join_set_error_string(mem_ctx
, r
,
1501 "failed to join domain over rpc: %s",
1502 get_friendly_nt_error_msg(status
));
1503 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_EXISTS
)) {
1504 return WERR_SETUP_ALREADY_JOINED
;
1506 return ntstatus_to_werror(status
);
1509 if (!libnet_join_joindomain_store_secrets(mem_ctx
, r
)) {
1510 return WERR_SETUP_NOT_JOINED
;
1514 if (r
->out
.domain_is_ad
) {
1515 ads_status
= libnet_join_post_processing_ads(mem_ctx
, r
);
1516 if (!ADS_ERR_OK(ads_status
)) {
1517 return WERR_GENERAL_FAILURE
;
1520 #endif /* WITH_ADS */
1525 /****************************************************************
1526 ****************************************************************/
1528 WERROR
libnet_Join(TALLOC_CTX
*mem_ctx
,
1529 struct libnet_JoinCtx
*r
)
1534 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx
, r
);
1537 werr
= libnet_join_pre_processing(mem_ctx
, r
);
1538 if (!W_ERROR_IS_OK(werr
)) {
1542 if (r
->in
.join_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1543 werr
= libnet_DomainJoin(mem_ctx
, r
);
1544 if (!W_ERROR_IS_OK(werr
)) {
1548 werr
= libnet_join_post_verify(mem_ctx
, r
);
1549 if (!W_ERROR_IS_OK(werr
)) {
1554 werr
= libnet_join_post_processing(mem_ctx
, r
);
1555 if (!W_ERROR_IS_OK(werr
)) {
1559 r
->out
.result
= werr
;
1562 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx
, r
);
1567 /****************************************************************
1568 ****************************************************************/
1570 static WERROR
libnet_DomainUnjoin(TALLOC_CTX
*mem_ctx
,
1571 struct libnet_UnjoinCtx
*r
)
1575 if (!r
->in
.domain_sid
) {
1577 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid
)) {
1578 libnet_unjoin_set_error_string(mem_ctx
, r
,
1579 "Unable to fetch domain sid: are we joined?");
1580 return WERR_SETUP_NOT_JOINED
;
1582 r
->in
.domain_sid
= sid_dup_talloc(mem_ctx
, &sid
);
1583 W_ERROR_HAVE_NO_MEMORY(r
->in
.domain_sid
);
1586 if (!r
->in
.dc_name
) {
1587 struct netr_DsRGetDCNameInfo
*info
;
1588 status
= dsgetdcname(mem_ctx
,
1592 DS_DIRECTORY_SERVICE_REQUIRED
|
1593 DS_WRITABLE_REQUIRED
|
1596 if (!NT_STATUS_IS_OK(status
)) {
1597 libnet_unjoin_set_error_string(mem_ctx
, r
,
1598 "failed to find DC for domain %s",
1600 get_friendly_nt_error_msg(status
));
1601 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1604 r
->in
.dc_name
= talloc_strdup(mem_ctx
,
1606 W_ERROR_HAVE_NO_MEMORY(r
->in
.dc_name
);
1609 status
= libnet_join_unjoindomain_rpc(mem_ctx
, r
);
1610 if (!NT_STATUS_IS_OK(status
)) {
1611 libnet_unjoin_set_error_string(mem_ctx
, r
,
1612 "failed to disable machine account via rpc: %s",
1613 get_friendly_nt_error_msg(status
));
1614 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
1615 return WERR_SETUP_NOT_JOINED
;
1617 return ntstatus_to_werror(status
);
1620 r
->out
.disabled_machine_account
= true;
1623 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE
) {
1624 ADS_STATUS ads_status
;
1625 libnet_unjoin_connect_ads(mem_ctx
, r
);
1626 ads_status
= libnet_unjoin_remove_machine_acct(mem_ctx
, r
);
1627 if (!ADS_ERR_OK(ads_status
)) {
1628 libnet_unjoin_set_error_string(mem_ctx
, r
,
1629 "failed to remove machine account from AD: %s",
1630 ads_errstr(ads_status
));
1632 r
->out
.deleted_machine_account
= true;
1634 r
->out
.dns_domain_name
= talloc_strdup(mem_ctx
,
1635 r
->in
.ads
->server
.realm
);
1636 W_ERROR_HAVE_NO_MEMORY(r
->out
.dns_domain_name
);
1639 #endif /* WITH_ADS */
1641 libnet_join_unjoindomain_remove_secrets(mem_ctx
, r
);
1646 /****************************************************************
1647 ****************************************************************/
1649 static WERROR
libnet_unjoin_pre_processing(TALLOC_CTX
*mem_ctx
,
1650 struct libnet_UnjoinCtx
*r
)
1652 if (!r
->in
.domain_name
) {
1653 libnet_unjoin_set_error_string(mem_ctx
, r
,
1654 "No domain name defined");
1655 return WERR_INVALID_PARAM
;
1658 if (r
->in
.modify_config
&& !lp_config_backend_is_registry()) {
1659 libnet_unjoin_set_error_string(mem_ctx
, r
,
1660 "Configuration manipulation requested but not "
1661 "supported by backend");
1662 return WERR_NOT_SUPPORTED
;
1666 return WERR_SETUP_DOMAIN_CONTROLLER
;
1669 if (!secrets_init()) {
1670 libnet_unjoin_set_error_string(mem_ctx
, r
,
1671 "Unable to open secrets database");
1672 return WERR_CAN_NOT_COMPLETE
;
1678 /****************************************************************
1679 ****************************************************************/
1681 static WERROR
libnet_unjoin_post_processing(TALLOC_CTX
*mem_ctx
,
1682 struct libnet_UnjoinCtx
*r
)
1684 saf_delete(r
->out
.netbios_domain_name
);
1685 saf_delete(r
->out
.dns_domain_name
);
1687 return libnet_unjoin_config(r
);
1690 /****************************************************************
1691 ****************************************************************/
1693 WERROR
libnet_Unjoin(TALLOC_CTX
*mem_ctx
,
1694 struct libnet_UnjoinCtx
*r
)
1699 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx
, r
);
1702 werr
= libnet_unjoin_pre_processing(mem_ctx
, r
);
1703 if (!W_ERROR_IS_OK(werr
)) {
1707 if (r
->in
.unjoin_flags
& WKSSVC_JOIN_FLAGS_JOIN_TYPE
) {
1708 werr
= libnet_DomainUnjoin(mem_ctx
, r
);
1709 if (!W_ERROR_IS_OK(werr
)) {
1710 libnet_unjoin_config(r
);
1715 werr
= libnet_unjoin_post_processing(mem_ctx
, r
);
1716 if (!W_ERROR_IS_OK(werr
)) {
1721 r
->out
.result
= werr
;
1724 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx
, r
);