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_join.h"
23 #include "libnet/libnet_proto.h"
25 /****************************************************************
26 ****************************************************************/
28 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
29 struct libnet_JoinCtx *r,
30 const char *format, ...)
34 if (r->out.error_string) {
38 va_start(args, format);
39 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
43 /****************************************************************
44 ****************************************************************/
46 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
47 struct libnet_UnjoinCtx *r,
48 const char *format, ...)
52 if (r->out.error_string) {
56 va_start(args, format);
57 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
63 /****************************************************************
64 ****************************************************************/
66 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
67 const char *netbios_domain_name,
69 const char *user_name,
74 ADS_STRUCT *my_ads = NULL;
76 my_ads = ads_init(dns_domain_name,
80 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
84 SAFE_FREE(my_ads->auth.user_name);
85 my_ads->auth.user_name = SMB_STRDUP(user_name);
89 SAFE_FREE(my_ads->auth.password);
90 my_ads->auth.password = SMB_STRDUP(password);
93 status = ads_connect(my_ads);
94 if (!ADS_ERR_OK(status)) {
103 /****************************************************************
104 ****************************************************************/
106 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
107 struct libnet_JoinCtx *r)
112 ads_destroy(&r->in.ads);
115 status = libnet_connect_ads(r->in.domain_name,
119 r->in.admin_password,
121 if (!ADS_ERR_OK(status)) {
122 libnet_join_set_error_string(mem_ctx, r,
123 "failed to connect to AD: %s",
130 /****************************************************************
131 ****************************************************************/
133 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
134 struct libnet_UnjoinCtx *r)
139 ads_destroy(&r->in.ads);
142 status = libnet_connect_ads(r->in.domain_name,
146 r->in.admin_password,
148 if (!ADS_ERR_OK(status)) {
149 libnet_unjoin_set_error_string(mem_ctx, r,
150 "failed to connect to AD: %s",
157 /****************************************************************
158 ****************************************************************/
160 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
161 struct libnet_JoinCtx *r)
164 LDAPMessage *res = NULL;
165 const char *attrs[] = { "dn", NULL };
167 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
168 if (!ADS_ERR_OK(status)) {
172 if (ads_count_replies(r->in.ads, res) != 1) {
173 ads_msgfree(r->in.ads, res);
174 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
177 status = ads_create_machine_acct(r->in.ads,
180 ads_msgfree(r->in.ads, res);
182 if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
183 (status.err.rc == LDAP_ALREADY_EXISTS)) {
184 status = ADS_SUCCESS;
190 /****************************************************************
191 ****************************************************************/
193 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
194 struct libnet_UnjoinCtx *r)
199 status = libnet_unjoin_connect_ads(mem_ctx, r);
200 if (!ADS_ERR_OK(status)) {
205 status = ads_leave_realm(r->in.ads, r->in.machine_name);
206 if (!ADS_ERR_OK(status)) {
207 libnet_unjoin_set_error_string(mem_ctx, r,
208 "failed to leave realm: %s",
216 /****************************************************************
217 ****************************************************************/
219 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
220 struct libnet_JoinCtx *r)
223 LDAPMessage *res = NULL;
226 if (!r->in.machine_name) {
227 return ADS_ERROR(LDAP_NO_MEMORY);
230 status = ads_find_machine_acct(r->in.ads,
233 if (!ADS_ERR_OK(status)) {
237 if (ads_count_replies(r->in.ads, res) != 1) {
238 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
242 dn = ads_get_dn(r->in.ads, res);
244 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
248 TALLOC_FREE(r->out.dn);
249 r->out.dn = talloc_strdup(mem_ctx, dn);
251 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
256 ads_msgfree(r->in.ads, res);
257 ads_memfree(r->in.ads, dn);
262 /****************************************************************
263 ****************************************************************/
265 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
266 struct libnet_JoinCtx *r)
271 const char *spn_array[3] = {NULL, NULL, NULL};
275 status = libnet_join_connect_ads(mem_ctx, r);
276 if (!ADS_ERR_OK(status)) {
281 status = libnet_join_find_machine_acct(mem_ctx, r);
282 if (!ADS_ERR_OK(status)) {
286 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
288 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
293 if (name_to_fqdn(my_fqdn, r->in.machine_name) &&
294 !strequal(my_fqdn, r->in.machine_name)) {
297 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
299 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
304 mods = ads_init_mods(mem_ctx);
306 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
309 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
310 if (!ADS_ERR_OK(status)) {
311 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
314 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
316 if (!ADS_ERR_OK(status)) {
317 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
320 return ads_gen_mod(r->in.ads, r->out.dn, mods);
323 /****************************************************************
324 ****************************************************************/
326 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
327 struct libnet_JoinCtx *r)
332 if (!r->in.create_upn) {
337 status = libnet_join_connect_ads(mem_ctx, r);
338 if (!ADS_ERR_OK(status)) {
343 status = libnet_join_find_machine_acct(mem_ctx, r);
344 if (!ADS_ERR_OK(status)) {
349 r->in.upn = talloc_asprintf(mem_ctx,
352 r->out.dns_domain_name);
354 return ADS_ERROR(LDAP_NO_MEMORY);
358 mods = ads_init_mods(mem_ctx);
360 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
363 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
364 if (!ADS_ERR_OK(status)) {
365 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
368 return ads_gen_mod(r->in.ads, r->out.dn, mods);
372 /****************************************************************
373 ****************************************************************/
375 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
376 struct libnet_JoinCtx *r)
382 if (!r->in.os_name || !r->in.os_version ) {
387 status = libnet_join_connect_ads(mem_ctx, r);
388 if (!ADS_ERR_OK(status)) {
393 status = libnet_join_find_machine_acct(mem_ctx, r);
394 if (!ADS_ERR_OK(status)) {
398 mods = ads_init_mods(mem_ctx);
400 return ADS_ERROR(LDAP_NO_MEMORY);
403 os_sp = talloc_asprintf(mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
405 return ADS_ERROR(LDAP_NO_MEMORY);
408 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
410 if (!ADS_ERR_OK(status)) {
414 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
416 if (!ADS_ERR_OK(status)) {
420 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
422 if (!ADS_ERR_OK(status)) {
426 return ads_gen_mod(r->in.ads, r->out.dn, mods);
429 /****************************************************************
430 ****************************************************************/
432 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
433 struct libnet_JoinCtx *r)
435 if (!lp_use_kerberos_keytab()) {
439 if (!ads_keytab_create_default(r->in.ads)) {
446 /****************************************************************
447 ****************************************************************/
449 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
450 struct libnet_JoinCtx *r)
452 uint32_t domain_func;
454 const char *salt = NULL;
455 char *std_salt = NULL;
457 status = ads_domain_func_level(r->in.ads, &domain_func);
458 if (!ADS_ERR_OK(status)) {
459 libnet_join_set_error_string(mem_ctx, r,
460 "failed to determine domain functional level: %s",
465 std_salt = kerberos_standard_des_salt();
467 libnet_join_set_error_string(mem_ctx, r,
468 "failed to obtain standard DES salt");
472 salt = talloc_strdup(mem_ctx, std_salt);
479 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
482 upn = ads_get_upn(r->in.ads, mem_ctx,
485 salt = talloc_strdup(mem_ctx, upn);
492 return kerberos_secrets_store_des_salt(salt);
495 /****************************************************************
496 ****************************************************************/
498 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
499 struct libnet_JoinCtx *r)
503 status = libnet_join_set_machine_spn(mem_ctx, r);
504 if (!ADS_ERR_OK(status)) {
505 libnet_join_set_error_string(mem_ctx, r,
506 "failed to set machine spn: %s",
511 status = libnet_join_set_os_attributes(mem_ctx, r);
512 if (!ADS_ERR_OK(status)) {
513 libnet_join_set_error_string(mem_ctx, r,
514 "failed to set machine os attributes: %s",
519 status = libnet_join_set_machine_upn(mem_ctx, r);
520 if (!ADS_ERR_OK(status)) {
521 libnet_join_set_error_string(mem_ctx, r,
522 "failed to set machine upn: %s",
527 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
528 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
531 if (!libnet_join_create_keytab(mem_ctx, r)) {
532 libnet_join_set_error_string(mem_ctx, r,
533 "failed to create kerberos keytab");
534 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
539 #endif /* WITH_ADS */
541 /****************************************************************
542 ****************************************************************/
544 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
545 struct libnet_JoinCtx *r)
547 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
553 if (!secrets_store_machine_password(r->in.machine_password,
554 r->out.netbios_domain_name,
563 /****************************************************************
564 ****************************************************************/
566 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
567 struct libnet_JoinCtx *r)
569 struct cli_state *cli = NULL;
570 struct rpc_pipe_client *pipe_hnd = NULL;
571 POLICY_HND sam_pol, domain_pol, user_pol, lsa_pol;
572 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
574 const char *const_acct_name;
576 uint32 num_rids, *name_types, *user_rids;
577 uint32 flags = 0x3e8;
578 uint32 acb_info = ACB_WSTRUST;
579 uint32 fields_present;
581 SAM_USERINFO_CTR ctr;
582 SAM_USER_INFO_25 p25;
583 const int infolevel = 25;
584 struct MD5Context md5ctx;
586 DATA_BLOB digested_session_key;
587 uchar md4_trust_password[16];
589 if (!r->in.machine_password) {
590 r->in.machine_password = talloc_strdup(mem_ctx, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
591 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
594 status = cli_full_connection(&cli, NULL,
600 r->in.admin_password,
604 if (!NT_STATUS_IS_OK(status)) {
608 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
613 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
614 SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
615 if (!NT_STATUS_IS_OK(status)) {
619 status = rpccli_lsa_query_info_policy2(pipe_hnd, mem_ctx, &lsa_pol,
621 &r->out.netbios_domain_name,
622 &r->out.dns_domain_name,
627 if (NT_STATUS_IS_OK(status)) {
628 r->out.domain_is_ad = true;
631 if (!NT_STATUS_IS_OK(status)) {
632 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &lsa_pol,
634 &r->out.netbios_domain_name,
636 if (!NT_STATUS_IS_OK(status)) {
641 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
642 cli_rpc_pipe_close(pipe_hnd);
644 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
649 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
650 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
651 if (!NT_STATUS_IS_OK(status)) {
655 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
656 SEC_RIGHTS_MAXIMUM_ALLOWED,
659 if (!NT_STATUS_IS_OK(status)) {
663 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
664 strlower_m(acct_name);
665 const_acct_name = acct_name;
667 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
668 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx,
670 acct_name, ACB_WSTRUST,
671 0xe005000b, &user_pol,
673 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
674 if (!(r->in.join_flags &
675 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
680 if (NT_STATUS_IS_OK(status)) {
681 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
685 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
686 &domain_pol, flags, 1,
688 &num_rids, &user_rids, &name_types);
689 if (!NT_STATUS_IS_OK(status)) {
693 if (name_types[0] != SID_NAME_USER) {
694 status = NT_STATUS_INVALID_WORKSTATION;
698 user_rid = user_rids[0];
700 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
701 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
703 if (!NT_STATUS_IS_OK(status)) {
707 E_md4hash(r->in.machine_password, md4_trust_password);
708 encode_pw_buffer(pwbuf, r->in.machine_password, STR_UNICODE);
710 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
711 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
714 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
715 MD5Update(&md5ctx, cli->user_session_key.data,
716 cli->user_session_key.length);
717 MD5Final(digested_session_key.data, &md5ctx);
719 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
720 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
722 acb_info |= ACB_PWNOEXP;
723 if (r->out.domain_is_ad) {
724 #if !defined(ENCTYPE_ARCFOUR_HMAC)
725 acb_info |= ACB_USE_DES_KEY_ONLY;
733 fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
734 init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
736 ctr.switch_value = infolevel;
737 ctr.info.id25 = &p25;
739 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
740 infolevel, &cli->user_session_key,
742 if (!NT_STATUS_IS_OK(status)) {
746 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
747 cli_rpc_pipe_close(pipe_hnd);
749 status = NT_STATUS_OK;
758 /****************************************************************
759 ****************************************************************/
761 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
762 struct libnet_UnjoinCtx *r)
764 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
768 if (!secrets_delete_domain_sid(lp_workgroup())) {
775 /****************************************************************
776 ****************************************************************/
778 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
779 struct libnet_UnjoinCtx *r)
781 struct cli_state *cli = NULL;
782 struct rpc_pipe_client *pipe_hnd = NULL;
783 POLICY_HND sam_pol, domain_pol, user_pol;
784 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
786 uint32 flags = 0x3e8;
787 const char *const_acct_name;
789 uint32 num_rids, *name_types, *user_rids;
790 SAM_USERINFO_CTR ctr, *qctr = NULL;
791 SAM_USER_INFO_16 p16;
793 status = cli_full_connection(&cli, NULL,
799 r->in.admin_password,
802 if (!NT_STATUS_IS_OK(status)) {
806 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
811 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
812 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
813 if (!NT_STATUS_IS_OK(status)) {
817 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
818 SEC_RIGHTS_MAXIMUM_ALLOWED,
821 if (!NT_STATUS_IS_OK(status)) {
825 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
826 strlower_m(acct_name);
827 const_acct_name = acct_name;
829 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
830 &domain_pol, flags, 1,
832 &num_rids, &user_rids, &name_types);
833 if (!NT_STATUS_IS_OK(status)) {
837 if (name_types[0] != SID_NAME_USER) {
838 status = NT_STATUS_INVALID_WORKSTATION;
842 user_rid = user_rids[0];
844 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
845 SEC_RIGHTS_MAXIMUM_ALLOWED,
846 user_rid, &user_pol);
847 if (!NT_STATUS_IS_OK(status)) {
851 status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx,
852 &user_pol, 16, &qctr);
853 if (!NT_STATUS_IS_OK(status)) {
854 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
859 ctr.switch_value = 16;
860 ctr.info.id16 = &p16;
862 p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
864 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
865 &cli->user_session_key, &ctr);
867 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
871 rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
872 rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
873 cli_rpc_pipe_close(pipe_hnd);
883 /****************************************************************
884 ****************************************************************/
886 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
890 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
892 werr = libnet_conf_set_global_parameter("security", "user");
893 W_ERROR_NOT_OK_RETURN(werr);
895 werr = libnet_conf_set_global_parameter("workgroup",
900 werr = libnet_conf_set_global_parameter("security", "domain");
901 W_ERROR_NOT_OK_RETURN(werr);
903 werr = libnet_conf_set_global_parameter("workgroup",
904 r->out.netbios_domain_name);
905 W_ERROR_NOT_OK_RETURN(werr);
907 if (r->out.domain_is_ad) {
908 werr = libnet_conf_set_global_parameter("security", "ads");
909 W_ERROR_NOT_OK_RETURN(werr);
911 werr = libnet_conf_set_global_parameter("realm",
912 r->out.dns_domain_name);
913 W_ERROR_NOT_OK_RETURN(werr);
919 /****************************************************************
920 ****************************************************************/
922 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
924 WERROR werr = WERR_OK;
926 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
928 werr = libnet_conf_set_global_parameter("security", "user");
929 W_ERROR_NOT_OK_RETURN(werr);
932 libnet_conf_delete_parameter(GLOBAL_NAME, "realm");
937 /****************************************************************
938 ****************************************************************/
940 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
944 if (!W_ERROR_IS_OK(r->out.result)) {
945 return r->out.result;
948 if (!r->in.modify_config) {
952 werr = do_join_modify_vals_config(r);
953 if (!W_ERROR_IS_OK(werr)) {
957 r->out.modified_config = true;
958 r->out.result = werr;
963 /****************************************************************
964 ****************************************************************/
966 static WERROR do_UnjoinConfig(struct libnet_UnjoinCtx *r)
970 if (!W_ERROR_IS_OK(r->out.result)) {
971 return r->out.result;
974 if (!r->in.modify_config) {
978 werr = do_unjoin_modify_vals_config(r);
979 if (!W_ERROR_IS_OK(werr)) {
983 r->out.modified_config = true;
984 r->out.result = werr;
989 /****************************************************************
990 ****************************************************************/
992 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
995 ads_destroy(&r->in.ads);
1001 /****************************************************************
1002 ****************************************************************/
1004 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1007 ads_destroy(&r->in.ads);
1013 /****************************************************************
1014 ****************************************************************/
1016 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1017 struct libnet_JoinCtx **r)
1019 struct libnet_JoinCtx *ctx;
1021 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1026 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1028 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1029 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1036 /****************************************************************
1037 ****************************************************************/
1039 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1040 struct libnet_UnjoinCtx **r)
1042 struct libnet_UnjoinCtx *ctx;
1044 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1049 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1051 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1052 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1059 /****************************************************************
1060 ****************************************************************/
1062 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1063 struct libnet_JoinCtx *r)
1067 ADS_STATUS ads_status;
1068 #endif /* WITH_ADS */
1070 if (!r->in.dc_name) {
1071 struct DS_DOMAIN_CONTROLLER_INFO *info;
1072 status = dsgetdcname(mem_ctx,
1077 DS_DIRECTORY_SERVICE_REQUIRED |
1078 DS_WRITABLE_REQUIRED |
1081 if (!NT_STATUS_IS_OK(status)) {
1082 libnet_join_set_error_string(mem_ctx, r,
1083 "failed to find DC: %s",
1085 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1088 r->in.dc_name = talloc_strdup(mem_ctx,
1089 info->domain_controller_name);
1090 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1094 if (r->in.account_ou) {
1096 ads_status = libnet_join_connect_ads(mem_ctx, r);
1097 if (!ADS_ERR_OK(ads_status)) {
1098 return WERR_DEFAULT_JOIN_REQUIRED;
1101 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1102 if (!ADS_ERR_OK(ads_status)) {
1103 libnet_join_set_error_string(mem_ctx, r,
1104 "failed to precreate account in ou %s: %s",
1106 ads_errstr(ads_status));
1107 return WERR_DEFAULT_JOIN_REQUIRED;
1110 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1112 #endif /* WITH_ADS */
1114 status = libnet_join_joindomain_rpc(mem_ctx, r);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 libnet_join_set_error_string(mem_ctx, r,
1117 "failed to join domain over rpc: %s",
1119 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1120 return WERR_SETUP_ALREADY_JOINED;
1122 return ntstatus_to_werror(status);
1125 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1126 return WERR_SETUP_NOT_JOINED;
1130 if (r->out.domain_is_ad) {
1131 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1132 if (!ADS_ERR_OK(ads_status)) {
1133 return WERR_GENERAL_FAILURE;
1136 #endif /* WITH_ADS */
1141 /****************************************************************
1142 ****************************************************************/
1144 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1145 struct libnet_JoinCtx *r)
1149 if (!r->in.domain_name) {
1150 return WERR_INVALID_PARAM;
1153 if (r->in.modify_config && !lp_include_registry_globals()) {
1154 return WERR_NOT_SUPPORTED;
1158 return WERR_SETUP_DOMAIN_CONTROLLER;
1161 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1162 werr = libnet_DomainJoin(mem_ctx, r);
1163 if (!W_ERROR_IS_OK(werr)) {
1168 werr = do_JoinConfig(r);
1169 if (!W_ERROR_IS_OK(werr)) {
1176 /****************************************************************
1177 ****************************************************************/
1179 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1180 struct libnet_UnjoinCtx *r)
1184 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 libnet_unjoin_set_error_string(mem_ctx, r,
1187 "failed to unjoin domain: %s",
1189 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1190 return WERR_SETUP_NOT_JOINED;
1192 return ntstatus_to_werror(status);
1196 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
1197 ADS_STATUS ads_status;
1198 libnet_unjoin_connect_ads(mem_ctx, r);
1199 ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
1200 if (!ADS_ERR_OK(ads_status)) {
1201 libnet_unjoin_set_error_string(mem_ctx, r,
1202 "failed to remove machine account from AD: %s",
1203 ads_errstr(ads_status));
1206 #endif /* WITH_ADS */
1208 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
1213 /****************************************************************
1214 ****************************************************************/
1216 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
1217 struct libnet_UnjoinCtx *r)
1221 if (r->in.modify_config && !lp_include_registry_globals()) {
1222 return WERR_NOT_SUPPORTED;
1225 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1226 werr = libnet_DomainUnjoin(mem_ctx, r);
1227 if (!W_ERROR_IS_OK(werr)) {
1233 werr = do_UnjoinConfig(r);
1234 if (!W_ERROR_IS_OK(werr)) {