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, ...)
35 va_start(args, format);
36 tmp = talloc_vasprintf(mem_ctx, format, args);
39 TALLOC_FREE(r->out.error_string);
40 r->out.error_string = tmp;
43 /****************************************************************
44 ****************************************************************/
46 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
47 struct libnet_UnjoinCtx *r,
48 const char *format, ...)
53 va_start(args, format);
54 tmp = talloc_vasprintf(mem_ctx, format, args);
57 TALLOC_FREE(r->out.error_string);
58 r->out.error_string = tmp;
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 #endif /* HAVE_LDAP */
431 /****************************************************************
432 ****************************************************************/
434 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
435 struct libnet_JoinCtx *r)
437 if (!lp_use_kerberos_keytab()) {
441 if (!ads_keytab_create_default(r->in.ads)) {
444 #endif /* HAVE_KRB5 */
450 /****************************************************************
451 ****************************************************************/
453 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
454 struct libnet_JoinCtx *r)
456 uint32_t domain_func;
458 const char *salt = NULL;
459 char *std_salt = NULL;
461 status = ads_domain_func_level(r->in.ads, &domain_func);
462 if (!ADS_ERR_OK(status)) {
463 libnet_join_set_error_string(mem_ctx, r,
464 "Failed to determine domain functional level!");
468 std_salt = kerberos_standard_des_salt();
470 libnet_join_set_error_string(mem_ctx, r,
471 "failed to obtain standard DES salt");
475 salt = talloc_strdup(mem_ctx, std_salt);
482 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
485 upn = ads_get_upn(r->in.ads, mem_ctx,
488 salt = talloc_strdup(mem_ctx, upn);
495 return kerberos_secrets_store_des_salt(salt);
498 #endif /* HAVE_KRB5 */
500 /****************************************************************
501 ****************************************************************/
503 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
504 struct libnet_JoinCtx *r)
506 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
512 if (!secrets_store_machine_password(r->in.machine_password,
513 r->out.netbios_domain_name,
522 /****************************************************************
523 ****************************************************************/
525 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
526 struct libnet_JoinCtx *r)
528 struct cli_state *cli = NULL;
529 struct rpc_pipe_client *pipe_hnd = NULL;
530 POLICY_HND sam_pol, domain_pol, user_pol, lsa_pol;
531 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
533 const char *const_acct_name;
535 uint32 num_rids, *name_types, *user_rids;
536 uint32 flags = 0x3e8;
537 uint32 acb_info = ACB_WSTRUST;
538 uint32 fields_present;
540 SAM_USERINFO_CTR ctr;
541 SAM_USER_INFO_25 p25;
542 const int infolevel = 25;
543 struct MD5Context md5ctx;
545 DATA_BLOB digested_session_key;
546 uchar md4_trust_password[16];
548 if (!r->in.machine_password) {
549 r->in.machine_password = talloc_strdup(mem_ctx, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
550 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
553 status = cli_full_connection(&cli, NULL,
559 r->in.admin_password,
563 if (!NT_STATUS_IS_OK(status)) {
567 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
572 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
573 SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
574 if (!NT_STATUS_IS_OK(status)) {
578 status = rpccli_lsa_query_info_policy2(pipe_hnd, mem_ctx, &lsa_pol,
580 &r->out.netbios_domain_name,
581 &r->out.dns_domain_name,
586 if (NT_STATUS_IS_OK(status)) {
587 r->out.domain_is_ad = true;
590 if (!NT_STATUS_IS_OK(status)) {
591 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &lsa_pol,
593 &r->out.netbios_domain_name,
595 if (!NT_STATUS_IS_OK(status)) {
600 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
601 cli_rpc_pipe_close(pipe_hnd);
603 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
608 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
609 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
610 if (!NT_STATUS_IS_OK(status)) {
614 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
615 SEC_RIGHTS_MAXIMUM_ALLOWED,
618 if (!NT_STATUS_IS_OK(status)) {
622 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
623 strlower_m(acct_name);
624 const_acct_name = acct_name;
626 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
627 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx,
629 acct_name, ACB_WSTRUST,
630 0xe005000b, &user_pol,
632 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
633 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
638 if (NT_STATUS_IS_OK(status)) {
639 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
643 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
644 &domain_pol, flags, 1,
646 &num_rids, &user_rids, &name_types);
647 if (!NT_STATUS_IS_OK(status)) {
651 if (name_types[0] != SID_NAME_USER) {
652 status = NT_STATUS_INVALID_WORKSTATION;
656 user_rid = user_rids[0];
658 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
659 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
661 if (!NT_STATUS_IS_OK(status)) {
665 E_md4hash(r->in.machine_password, md4_trust_password);
666 encode_pw_buffer(pwbuf, r->in.machine_password, STR_UNICODE);
668 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
669 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
672 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
673 MD5Update(&md5ctx, cli->user_session_key.data,
674 cli->user_session_key.length);
675 MD5Final(digested_session_key.data, &md5ctx);
677 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
678 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
680 acb_info |= ACB_PWNOEXP;
682 if ( dom_type == ND_TYPE_AD ) {
683 #if !defined(ENCTYPE_ARCFOUR_HMAC)
684 acb_info |= ACB_USE_DES_KEY_ONLY;
692 fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
693 init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
695 ctr.switch_value = infolevel;
696 ctr.info.id25 = &p25;
698 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
699 infolevel, &cli->user_session_key,
701 if (!NT_STATUS_IS_OK(status)) {
705 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
706 cli_rpc_pipe_close(pipe_hnd);
708 status = NT_STATUS_OK;
717 /****************************************************************
718 ****************************************************************/
720 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
721 struct libnet_UnjoinCtx *r)
723 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
727 if (!secrets_delete_domain_sid(lp_workgroup())) {
734 /****************************************************************
735 ****************************************************************/
737 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
738 struct libnet_UnjoinCtx *r)
740 struct cli_state *cli = NULL;
741 struct rpc_pipe_client *pipe_hnd = NULL;
742 POLICY_HND sam_pol, domain_pol, user_pol;
743 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
745 uint32 flags = 0x3e8;
746 const char *const_acct_name;
748 uint32 num_rids, *name_types, *user_rids;
749 SAM_USERINFO_CTR ctr, *qctr = NULL;
750 SAM_USER_INFO_16 p16;
752 status = cli_full_connection(&cli, NULL,
758 r->in.admin_password,
761 if (!NT_STATUS_IS_OK(status)) {
765 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
770 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
771 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
772 if (!NT_STATUS_IS_OK(status)) {
776 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
777 SEC_RIGHTS_MAXIMUM_ALLOWED,
780 if (!NT_STATUS_IS_OK(status)) {
784 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
785 strlower_m(acct_name);
786 const_acct_name = acct_name;
788 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
789 &domain_pol, flags, 1,
791 &num_rids, &user_rids, &name_types);
792 if (!NT_STATUS_IS_OK(status)) {
796 if (name_types[0] != SID_NAME_USER) {
797 status = NT_STATUS_INVALID_WORKSTATION;
801 user_rid = user_rids[0];
803 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
804 SEC_RIGHTS_MAXIMUM_ALLOWED,
805 user_rid, &user_pol);
806 if (!NT_STATUS_IS_OK(status)) {
810 status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx,
811 &user_pol, 16, &qctr);
812 if (!NT_STATUS_IS_OK(status)) {
813 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
818 ctr.switch_value = 16;
819 ctr.info.id16 = &p16;
821 p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
823 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
824 &cli->user_session_key, &ctr);
826 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
830 rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
831 rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
832 cli_rpc_pipe_close(pipe_hnd);
842 /****************************************************************
843 ****************************************************************/
845 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
849 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
851 werr = libnet_conf_set_global_parameter("security", "user");
852 W_ERROR_NOT_OK_RETURN(werr);
854 werr = libnet_conf_set_global_parameter("workgroup",
859 werr = libnet_conf_set_global_parameter("security", "domain");
860 W_ERROR_NOT_OK_RETURN(werr);
862 werr = libnet_conf_set_global_parameter("workgroup",
863 r->out.netbios_domain_name);
864 W_ERROR_NOT_OK_RETURN(werr);
866 if (r->out.domain_is_ad) {
867 werr = libnet_conf_set_global_parameter("security", "ads");
868 W_ERROR_NOT_OK_RETURN(werr);
870 werr = libnet_conf_set_global_parameter("realm",
871 r->out.dns_domain_name);
872 W_ERROR_NOT_OK_RETURN(werr);
878 /****************************************************************
879 ****************************************************************/
881 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
883 WERROR werr = WERR_OK;
885 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
887 werr = libnet_conf_set_global_parameter("security", "user");
888 W_ERROR_NOT_OK_RETURN(werr);
891 libnet_conf_delete_parameter(GLOBAL_NAME, "realm");
896 /****************************************************************
897 ****************************************************************/
899 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
903 if (!W_ERROR_IS_OK(r->out.result)) {
904 return r->out.result;
907 if (!r->in.modify_config) {
911 werr = do_join_modify_vals_config(r);
912 if (!W_ERROR_IS_OK(werr)) {
916 r->out.modified_config = true;
917 r->out.result = werr;
922 /****************************************************************
923 ****************************************************************/
925 static WERROR do_UnjoinConfig(struct libnet_UnjoinCtx *r)
929 if (!W_ERROR_IS_OK(r->out.result)) {
930 return r->out.result;
933 if (!r->in.modify_config) {
937 werr = do_unjoin_modify_vals_config(r);
938 if (!W_ERROR_IS_OK(werr)) {
942 r->out.modified_config = true;
943 r->out.result = werr;
948 /****************************************************************
949 ****************************************************************/
951 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
954 ads_destroy(&r->in.ads);
960 /****************************************************************
961 ****************************************************************/
963 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
966 ads_destroy(&r->in.ads);
972 /****************************************************************
973 ****************************************************************/
975 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
976 struct libnet_JoinCtx **r)
978 struct libnet_JoinCtx *ctx;
980 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
985 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
987 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
988 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
995 /****************************************************************
996 ****************************************************************/
998 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
999 struct libnet_UnjoinCtx **r)
1001 struct libnet_UnjoinCtx *ctx;
1003 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1008 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1010 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1011 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1018 /****************************************************************
1019 ****************************************************************/
1021 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1022 struct libnet_JoinCtx *r)
1026 ADS_STATUS ads_status;
1028 if (r->in.account_ou) {
1029 ads_status = libnet_join_connect_ads(mem_ctx, r);
1030 if (!ADS_ERR_OK(ads_status)) {
1031 return WERR_GENERAL_FAILURE;
1033 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1034 if (!ADS_ERR_OK(ads_status)) {
1035 libnet_join_set_error_string(mem_ctx, r,
1036 "failed to precreate account in ou %s: %s",
1038 ads_errstr(ads_status));
1039 return WERR_GENERAL_FAILURE;
1042 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1044 #endif /* HAVE_LDAP */
1045 status = libnet_join_joindomain_rpc(mem_ctx, r);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1048 return WERR_SETUP_ALREADY_JOINED;
1050 return ntstatus_to_werror(status);
1053 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1054 return WERR_SETUP_NOT_JOINED;
1058 ads_status = libnet_join_set_machine_spn(mem_ctx, r);
1059 if (!ADS_ERR_OK(ads_status)) {
1060 libnet_join_set_error_string(mem_ctx, r,
1061 "failed to set machine spn: %s",
1062 ads_errstr(ads_status));
1063 return WERR_GENERAL_FAILURE;
1066 ads_status = libnet_join_set_os_attributes(mem_ctx, r);
1067 if (!ADS_ERR_OK(ads_status)) {
1068 libnet_join_set_error_string(mem_ctx, r,
1069 "failed to set machine os attributes: %s",
1070 ads_errstr(ads_status));
1071 return WERR_GENERAL_FAILURE;
1074 ads_status = libnet_join_set_machine_upn(mem_ctx, r);
1075 if (!ADS_ERR_OK(ads_status)) {
1076 libnet_join_set_error_string(mem_ctx, r,
1077 "failed to set machine upn: %s",
1078 ads_errstr(ads_status));
1079 return WERR_GENERAL_FAILURE;
1083 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
1084 return WERR_GENERAL_FAILURE;
1086 #endif /* HAVE_KRB5 */
1088 #endif /* HAVE_LDAP */
1089 if (!libnet_join_create_keytab(mem_ctx, r)) {
1090 libnet_join_set_error_string(mem_ctx, r,
1091 "failed to create kerberos keytab");
1092 return WERR_GENERAL_FAILURE;
1098 /****************************************************************
1099 ****************************************************************/
1101 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1102 struct libnet_JoinCtx *r)
1106 if (!r->in.domain_name) {
1107 return WERR_INVALID_PARAM;
1110 if (r->in.modify_config && !lp_include_registry_globals()) {
1111 return WERR_NOT_SUPPORTED;
1115 return WERR_SETUP_DOMAIN_CONTROLLER;
1118 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1119 werr = libnet_DomainJoin(mem_ctx, r);
1120 if (!W_ERROR_IS_OK(werr)) {
1125 werr = do_JoinConfig(r);
1126 if (!W_ERROR_IS_OK(werr)) {
1133 /****************************************************************
1134 ****************************************************************/
1136 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1137 struct libnet_UnjoinCtx *r)
1141 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
1142 if (!NT_STATUS_IS_OK(status)) {
1143 libnet_unjoin_set_error_string(mem_ctx, r,
1144 "failed to unjoin domain: %s",
1146 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1147 return WERR_SETUP_NOT_JOINED;
1149 return ntstatus_to_werror(status);
1153 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
1154 ADS_STATUS ads_status;
1155 libnet_unjoin_connect_ads(mem_ctx, r);
1156 ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
1157 if (!ADS_ERR_OK(ads_status)) {
1158 libnet_unjoin_set_error_string(mem_ctx, r,
1159 "failed to remove machine account from AD: %s",
1160 ads_errstr(ads_status));
1163 #endif /* HAVE_LDAP */
1164 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
1169 /****************************************************************
1170 ****************************************************************/
1172 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
1173 struct libnet_UnjoinCtx *r)
1177 if (r->in.modify_config && !lp_include_registry_globals()) {
1178 return WERR_NOT_SUPPORTED;
1181 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1182 werr = libnet_DomainUnjoin(mem_ctx, r);
1183 if (!W_ERROR_IS_OK(werr)) {
1189 werr = do_UnjoinConfig(r);
1190 if (!W_ERROR_IS_OK(werr)) {