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 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
28 struct libnet_JoinCtx *r,
29 const char *format, ...)
33 if (r->out.error_string) {
37 va_start(args, format);
38 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
42 /****************************************************************
43 ****************************************************************/
45 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
46 struct libnet_UnjoinCtx *r,
47 const char *format, ...)
51 if (r->out.error_string) {
55 va_start(args, format);
56 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
62 /****************************************************************
63 ****************************************************************/
65 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
66 const char *netbios_domain_name,
68 const char *user_name,
73 ADS_STRUCT *my_ads = NULL;
75 my_ads = ads_init(dns_domain_name,
79 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
83 SAFE_FREE(my_ads->auth.user_name);
84 my_ads->auth.user_name = SMB_STRDUP(user_name);
88 SAFE_FREE(my_ads->auth.password);
89 my_ads->auth.password = SMB_STRDUP(password);
92 status = ads_connect(my_ads);
93 if (!ADS_ERR_OK(status)) {
102 /****************************************************************
103 ****************************************************************/
105 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
106 struct libnet_JoinCtx *r)
111 ads_destroy(&r->in.ads);
114 status = libnet_connect_ads(r->in.domain_name,
118 r->in.admin_password,
120 if (!ADS_ERR_OK(status)) {
121 libnet_join_set_error_string(mem_ctx, r,
122 "failed to connect to AD: %s",
129 /****************************************************************
130 ****************************************************************/
132 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
133 struct libnet_UnjoinCtx *r)
138 ads_destroy(&r->in.ads);
141 status = libnet_connect_ads(r->in.domain_name,
145 r->in.admin_password,
147 if (!ADS_ERR_OK(status)) {
148 libnet_unjoin_set_error_string(mem_ctx, r,
149 "failed to connect to AD: %s",
156 /****************************************************************
157 ****************************************************************/
159 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
160 struct libnet_JoinCtx *r)
163 LDAPMessage *res = NULL;
164 const char *attrs[] = { "dn", NULL };
166 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
167 if (!ADS_ERR_OK(status)) {
171 if (ads_count_replies(r->in.ads, res) != 1) {
172 ads_msgfree(r->in.ads, res);
173 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
176 status = ads_create_machine_acct(r->in.ads,
179 ads_msgfree(r->in.ads, res);
181 if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
182 (status.err.rc == LDAP_ALREADY_EXISTS)) {
183 status = ADS_SUCCESS;
189 /****************************************************************
190 ****************************************************************/
192 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
193 struct libnet_UnjoinCtx *r)
198 status = libnet_unjoin_connect_ads(mem_ctx, r);
199 if (!ADS_ERR_OK(status)) {
204 status = ads_leave_realm(r->in.ads, r->in.machine_name);
205 if (!ADS_ERR_OK(status)) {
206 libnet_unjoin_set_error_string(mem_ctx, r,
207 "failed to leave realm: %s",
215 /****************************************************************
216 ****************************************************************/
218 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
219 struct libnet_JoinCtx *r)
222 LDAPMessage *res = NULL;
225 if (!r->in.machine_name) {
226 return ADS_ERROR(LDAP_NO_MEMORY);
229 status = ads_find_machine_acct(r->in.ads,
232 if (!ADS_ERR_OK(status)) {
236 if (ads_count_replies(r->in.ads, res) != 1) {
237 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
241 dn = ads_get_dn(r->in.ads, res);
243 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
247 TALLOC_FREE(r->out.dn);
248 r->out.dn = talloc_strdup(mem_ctx, dn);
250 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
255 ads_msgfree(r->in.ads, res);
256 ads_memfree(r->in.ads, dn);
261 /****************************************************************
262 ****************************************************************/
264 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
265 struct libnet_JoinCtx *r)
270 const char *spn_array[3] = {NULL, NULL, NULL};
274 status = libnet_join_connect_ads(mem_ctx, r);
275 if (!ADS_ERR_OK(status)) {
280 status = libnet_join_find_machine_acct(mem_ctx, r);
281 if (!ADS_ERR_OK(status)) {
285 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
287 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
292 if (name_to_fqdn(my_fqdn, r->in.machine_name) &&
293 !strequal(my_fqdn, r->in.machine_name)) {
296 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
298 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
303 mods = ads_init_mods(mem_ctx);
305 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
308 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
309 if (!ADS_ERR_OK(status)) {
310 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
313 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
315 if (!ADS_ERR_OK(status)) {
316 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
319 return ads_gen_mod(r->in.ads, r->out.dn, mods);
322 /****************************************************************
323 ****************************************************************/
325 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
326 struct libnet_JoinCtx *r)
331 if (!r->in.create_upn) {
336 status = libnet_join_connect_ads(mem_ctx, r);
337 if (!ADS_ERR_OK(status)) {
342 status = libnet_join_find_machine_acct(mem_ctx, r);
343 if (!ADS_ERR_OK(status)) {
348 r->in.upn = talloc_asprintf(mem_ctx,
351 r->out.dns_domain_name);
353 return ADS_ERROR(LDAP_NO_MEMORY);
357 mods = ads_init_mods(mem_ctx);
359 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
362 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
363 if (!ADS_ERR_OK(status)) {
364 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
367 return ads_gen_mod(r->in.ads, r->out.dn, mods);
371 /****************************************************************
372 ****************************************************************/
374 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
375 struct libnet_JoinCtx *r)
381 if (!r->in.os_name || !r->in.os_version ) {
386 status = libnet_join_connect_ads(mem_ctx, r);
387 if (!ADS_ERR_OK(status)) {
392 status = libnet_join_find_machine_acct(mem_ctx, r);
393 if (!ADS_ERR_OK(status)) {
397 mods = ads_init_mods(mem_ctx);
399 return ADS_ERROR(LDAP_NO_MEMORY);
402 os_sp = talloc_asprintf(mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
404 return ADS_ERROR(LDAP_NO_MEMORY);
407 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
409 if (!ADS_ERR_OK(status)) {
413 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
415 if (!ADS_ERR_OK(status)) {
419 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
421 if (!ADS_ERR_OK(status)) {
425 return ads_gen_mod(r->in.ads, r->out.dn, mods);
428 /****************************************************************
429 ****************************************************************/
431 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
432 struct libnet_JoinCtx *r)
434 if (!lp_use_kerberos_keytab()) {
438 if (!ads_keytab_create_default(r->in.ads)) {
445 /****************************************************************
446 ****************************************************************/
448 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
449 struct libnet_JoinCtx *r)
451 uint32_t domain_func;
453 const char *salt = NULL;
454 char *std_salt = NULL;
456 status = ads_domain_func_level(r->in.ads, &domain_func);
457 if (!ADS_ERR_OK(status)) {
458 libnet_join_set_error_string(mem_ctx, r,
459 "failed to determine domain functional level: %s",
464 std_salt = kerberos_standard_des_salt();
466 libnet_join_set_error_string(mem_ctx, r,
467 "failed to obtain standard DES salt");
471 salt = talloc_strdup(mem_ctx, std_salt);
478 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
481 upn = ads_get_upn(r->in.ads, mem_ctx,
484 salt = talloc_strdup(mem_ctx, upn);
491 return kerberos_secrets_store_des_salt(salt);
494 /****************************************************************
495 ****************************************************************/
497 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
498 struct libnet_JoinCtx *r)
502 status = libnet_join_set_machine_spn(mem_ctx, r);
503 if (!ADS_ERR_OK(status)) {
504 libnet_join_set_error_string(mem_ctx, r,
505 "failed to set machine spn: %s",
510 status = libnet_join_set_os_attributes(mem_ctx, r);
511 if (!ADS_ERR_OK(status)) {
512 libnet_join_set_error_string(mem_ctx, r,
513 "failed to set machine os attributes: %s",
518 status = libnet_join_set_machine_upn(mem_ctx, r);
519 if (!ADS_ERR_OK(status)) {
520 libnet_join_set_error_string(mem_ctx, r,
521 "failed to set machine upn: %s",
526 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
527 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
530 if (!libnet_join_create_keytab(mem_ctx, r)) {
531 libnet_join_set_error_string(mem_ctx, r,
532 "failed to create kerberos keytab");
533 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
538 #endif /* WITH_ADS */
540 /****************************************************************
541 ****************************************************************/
543 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
544 struct libnet_JoinCtx *r)
546 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
552 if (!secrets_store_machine_password(r->in.machine_password,
553 r->out.netbios_domain_name,
562 /****************************************************************
563 ****************************************************************/
565 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
566 struct libnet_JoinCtx *r)
568 struct cli_state *cli = NULL;
569 struct rpc_pipe_client *pipe_hnd = NULL;
570 POLICY_HND sam_pol, domain_pol, user_pol, lsa_pol;
571 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
573 const char *const_acct_name;
575 uint32 num_rids, *name_types, *user_rids;
576 uint32 flags = 0x3e8;
577 uint32 acb_info = ACB_WSTRUST;
578 uint32 fields_present;
580 SAM_USERINFO_CTR ctr;
581 SAM_USER_INFO_25 p25;
582 const int infolevel = 25;
583 struct MD5Context md5ctx;
585 DATA_BLOB digested_session_key;
586 uchar md4_trust_password[16];
588 if (!r->in.machine_password) {
589 r->in.machine_password = talloc_strdup(mem_ctx, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
590 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
593 status = cli_full_connection(&cli, NULL,
599 r->in.admin_password,
603 if (!NT_STATUS_IS_OK(status)) {
607 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
612 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
613 SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
614 if (!NT_STATUS_IS_OK(status)) {
618 status = rpccli_lsa_query_info_policy2(pipe_hnd, mem_ctx, &lsa_pol,
620 &r->out.netbios_domain_name,
621 &r->out.dns_domain_name,
626 if (NT_STATUS_IS_OK(status)) {
627 r->out.domain_is_ad = true;
630 if (!NT_STATUS_IS_OK(status)) {
631 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &lsa_pol,
633 &r->out.netbios_domain_name,
635 if (!NT_STATUS_IS_OK(status)) {
640 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
641 cli_rpc_pipe_close(pipe_hnd);
643 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
648 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
649 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
650 if (!NT_STATUS_IS_OK(status)) {
654 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
655 SEC_RIGHTS_MAXIMUM_ALLOWED,
658 if (!NT_STATUS_IS_OK(status)) {
662 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
663 strlower_m(acct_name);
664 const_acct_name = acct_name;
666 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
667 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx,
669 acct_name, ACB_WSTRUST,
670 0xe005000b, &user_pol,
672 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
673 if (!(r->in.join_flags &
674 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
679 if (NT_STATUS_IS_OK(status)) {
680 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
684 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
685 &domain_pol, flags, 1,
687 &num_rids, &user_rids, &name_types);
688 if (!NT_STATUS_IS_OK(status)) {
692 if (name_types[0] != SID_NAME_USER) {
693 status = NT_STATUS_INVALID_WORKSTATION;
697 user_rid = user_rids[0];
699 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
700 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
702 if (!NT_STATUS_IS_OK(status)) {
706 E_md4hash(r->in.machine_password, md4_trust_password);
707 encode_pw_buffer(pwbuf, r->in.machine_password, STR_UNICODE);
709 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
710 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
713 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
714 MD5Update(&md5ctx, cli->user_session_key.data,
715 cli->user_session_key.length);
716 MD5Final(digested_session_key.data, &md5ctx);
718 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
719 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
721 acb_info |= ACB_PWNOEXP;
722 if (r->out.domain_is_ad) {
723 #if !defined(ENCTYPE_ARCFOUR_HMAC)
724 acb_info |= ACB_USE_DES_KEY_ONLY;
732 fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
733 init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
735 ctr.switch_value = infolevel;
736 ctr.info.id25 = &p25;
738 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
739 infolevel, &cli->user_session_key,
741 if (!NT_STATUS_IS_OK(status)) {
745 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
746 cli_rpc_pipe_close(pipe_hnd);
748 status = NT_STATUS_OK;
757 /****************************************************************
758 ****************************************************************/
760 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
761 struct libnet_UnjoinCtx *r)
763 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
767 if (!secrets_delete_domain_sid(lp_workgroup())) {
774 /****************************************************************
775 ****************************************************************/
777 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
778 struct libnet_UnjoinCtx *r)
780 struct cli_state *cli = NULL;
781 struct rpc_pipe_client *pipe_hnd = NULL;
782 POLICY_HND sam_pol, domain_pol, user_pol;
783 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
785 uint32 flags = 0x3e8;
786 const char *const_acct_name;
788 uint32 num_rids, *name_types, *user_rids;
789 SAM_USERINFO_CTR ctr, *qctr = NULL;
790 SAM_USER_INFO_16 p16;
792 status = cli_full_connection(&cli, NULL,
798 r->in.admin_password,
801 if (!NT_STATUS_IS_OK(status)) {
805 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
810 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
811 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
812 if (!NT_STATUS_IS_OK(status)) {
816 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
817 SEC_RIGHTS_MAXIMUM_ALLOWED,
820 if (!NT_STATUS_IS_OK(status)) {
824 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
825 strlower_m(acct_name);
826 const_acct_name = acct_name;
828 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
829 &domain_pol, flags, 1,
831 &num_rids, &user_rids, &name_types);
832 if (!NT_STATUS_IS_OK(status)) {
836 if (name_types[0] != SID_NAME_USER) {
837 status = NT_STATUS_INVALID_WORKSTATION;
841 user_rid = user_rids[0];
843 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
844 SEC_RIGHTS_MAXIMUM_ALLOWED,
845 user_rid, &user_pol);
846 if (!NT_STATUS_IS_OK(status)) {
850 status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx,
851 &user_pol, 16, &qctr);
852 if (!NT_STATUS_IS_OK(status)) {
853 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
858 ctr.switch_value = 16;
859 ctr.info.id16 = &p16;
861 p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
863 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
864 &cli->user_session_key, &ctr);
866 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
870 rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
871 rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
872 cli_rpc_pipe_close(pipe_hnd);
882 /****************************************************************
883 ****************************************************************/
885 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
888 struct libnet_conf_ctx *ctx;
890 werr = libnet_conf_open(r, &ctx);
891 if (!W_ERROR_IS_OK(werr)) {
895 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
897 werr = libnet_conf_set_global_parameter(ctx, "security", "user");
898 if (!W_ERROR_IS_OK(werr)) {
902 werr = libnet_conf_set_global_parameter(ctx, "workgroup",
907 werr = libnet_conf_set_global_parameter(ctx, "security", "domain");
908 if (!W_ERROR_IS_OK(werr)) {
912 werr = libnet_conf_set_global_parameter(ctx, "workgroup",
913 r->out.netbios_domain_name);
914 if (!W_ERROR_IS_OK(werr)) {
918 if (r->out.domain_is_ad) {
919 werr = libnet_conf_set_global_parameter(ctx, "security", "ads");
920 if (!W_ERROR_IS_OK(werr)) {
924 werr = libnet_conf_set_global_parameter(ctx, "realm",
925 r->out.dns_domain_name);
929 libnet_conf_close(ctx);
933 /****************************************************************
934 ****************************************************************/
936 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
938 WERROR werr = WERR_OK;
939 struct libnet_conf_ctx *ctx;
941 werr = libnet_conf_open(r, &ctx);
942 if (!W_ERROR_IS_OK(werr)) {
946 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
948 werr = libnet_conf_set_global_parameter(ctx, "security", "user");
949 if (!W_ERROR_IS_OK(werr)) {
954 libnet_conf_delete_parameter(ctx, GLOBAL_NAME, "realm");
957 libnet_conf_close(ctx);
961 /****************************************************************
962 ****************************************************************/
964 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
968 if (!W_ERROR_IS_OK(r->out.result)) {
969 return r->out.result;
972 if (!r->in.modify_config) {
976 werr = do_join_modify_vals_config(r);
977 if (!W_ERROR_IS_OK(werr)) {
981 r->out.modified_config = true;
982 r->out.result = werr;
987 /****************************************************************
988 ****************************************************************/
990 static WERROR do_UnjoinConfig(struct libnet_UnjoinCtx *r)
994 if (!W_ERROR_IS_OK(r->out.result)) {
995 return r->out.result;
998 if (!r->in.modify_config) {
1002 werr = do_unjoin_modify_vals_config(r);
1003 if (!W_ERROR_IS_OK(werr)) {
1007 r->out.modified_config = true;
1008 r->out.result = werr;
1013 /****************************************************************
1014 ****************************************************************/
1016 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1019 ads_destroy(&r->in.ads);
1025 /****************************************************************
1026 ****************************************************************/
1028 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1031 ads_destroy(&r->in.ads);
1037 /****************************************************************
1038 ****************************************************************/
1040 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1041 struct libnet_JoinCtx **r)
1043 struct libnet_JoinCtx *ctx;
1045 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1050 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1052 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1053 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1060 /****************************************************************
1061 ****************************************************************/
1063 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1064 struct libnet_UnjoinCtx **r)
1066 struct libnet_UnjoinCtx *ctx;
1068 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1073 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1075 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1076 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1083 /****************************************************************
1084 ****************************************************************/
1086 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1087 struct libnet_JoinCtx *r)
1091 ADS_STATUS ads_status;
1092 #endif /* WITH_ADS */
1094 if (!r->in.dc_name) {
1095 struct DS_DOMAIN_CONTROLLER_INFO *info;
1096 status = dsgetdcname(mem_ctx,
1101 DS_DIRECTORY_SERVICE_REQUIRED |
1102 DS_WRITABLE_REQUIRED |
1105 if (!NT_STATUS_IS_OK(status)) {
1106 libnet_join_set_error_string(mem_ctx, r,
1107 "failed to find DC: %s",
1109 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1112 r->in.dc_name = talloc_strdup(mem_ctx,
1113 info->domain_controller_name);
1114 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1118 if (r->in.account_ou) {
1120 ads_status = libnet_join_connect_ads(mem_ctx, r);
1121 if (!ADS_ERR_OK(ads_status)) {
1122 return WERR_DEFAULT_JOIN_REQUIRED;
1125 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1126 if (!ADS_ERR_OK(ads_status)) {
1127 libnet_join_set_error_string(mem_ctx, r,
1128 "failed to precreate account in ou %s: %s",
1130 ads_errstr(ads_status));
1131 return WERR_DEFAULT_JOIN_REQUIRED;
1134 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1136 #endif /* WITH_ADS */
1138 status = libnet_join_joindomain_rpc(mem_ctx, r);
1139 if (!NT_STATUS_IS_OK(status)) {
1140 libnet_join_set_error_string(mem_ctx, r,
1141 "failed to join domain over rpc: %s",
1143 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1144 return WERR_SETUP_ALREADY_JOINED;
1146 return ntstatus_to_werror(status);
1149 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1150 return WERR_SETUP_NOT_JOINED;
1154 if (r->out.domain_is_ad) {
1155 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1156 if (!ADS_ERR_OK(ads_status)) {
1157 return WERR_GENERAL_FAILURE;
1160 #endif /* WITH_ADS */
1165 /****************************************************************
1166 ****************************************************************/
1168 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1169 struct libnet_JoinCtx *r)
1173 if (!r->in.domain_name) {
1174 return WERR_INVALID_PARAM;
1177 if (r->in.modify_config && !lp_include_registry_globals()) {
1178 return WERR_NOT_SUPPORTED;
1182 return WERR_SETUP_DOMAIN_CONTROLLER;
1185 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1186 werr = libnet_DomainJoin(mem_ctx, r);
1187 if (!W_ERROR_IS_OK(werr)) {
1192 werr = do_JoinConfig(r);
1193 if (!W_ERROR_IS_OK(werr)) {
1200 /****************************************************************
1201 ****************************************************************/
1203 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1204 struct libnet_UnjoinCtx *r)
1208 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
1209 if (!NT_STATUS_IS_OK(status)) {
1210 libnet_unjoin_set_error_string(mem_ctx, r,
1211 "failed to unjoin domain: %s",
1213 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1214 return WERR_SETUP_NOT_JOINED;
1216 return ntstatus_to_werror(status);
1220 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
1221 ADS_STATUS ads_status;
1222 libnet_unjoin_connect_ads(mem_ctx, r);
1223 ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
1224 if (!ADS_ERR_OK(ads_status)) {
1225 libnet_unjoin_set_error_string(mem_ctx, r,
1226 "failed to remove machine account from AD: %s",
1227 ads_errstr(ads_status));
1230 #endif /* WITH_ADS */
1232 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
1237 /****************************************************************
1238 ****************************************************************/
1240 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
1241 struct libnet_UnjoinCtx *r)
1245 if (r->in.modify_config && !lp_include_registry_globals()) {
1246 return WERR_NOT_SUPPORTED;
1249 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1250 werr = libnet_DomainUnjoin(mem_ctx, r);
1251 if (!W_ERROR_IS_OK(werr)) {
1257 werr = do_UnjoinConfig(r);
1258 if (!W_ERROR_IS_OK(werr)) {