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\n",
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\n",
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 return ads_leave_realm(r->in.ads, r->in.machine_name);
208 /****************************************************************
209 ****************************************************************/
211 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
212 struct libnet_JoinCtx *r)
215 LDAPMessage *res = NULL;
218 if (!r->in.machine_name) {
219 return ADS_ERROR(LDAP_NO_MEMORY);
222 status = ads_find_machine_acct(r->in.ads,
225 if (!ADS_ERR_OK(status)) {
229 if (ads_count_replies(r->in.ads, res) != 1) {
230 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
234 dn = ads_get_dn(r->in.ads, res);
236 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
240 TALLOC_FREE(r->out.dn);
241 r->out.dn = talloc_strdup(mem_ctx, dn);
243 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
248 ads_msgfree(r->in.ads, res);
249 ads_memfree(r->in.ads, dn);
254 /****************************************************************
255 ****************************************************************/
257 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
258 struct libnet_JoinCtx *r)
263 const char *spn_array[3] = {NULL, NULL, NULL};
267 status = libnet_join_connect_ads(mem_ctx, r);
268 if (!ADS_ERR_OK(status)) {
273 status = libnet_join_find_machine_acct(mem_ctx, r);
274 if (!ADS_ERR_OK(status)) {
278 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
280 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
285 if (name_to_fqdn(my_fqdn, r->in.machine_name) &&
286 !strequal(my_fqdn, r->in.machine_name)) {
289 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
291 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
296 mods = ads_init_mods(mem_ctx);
298 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
301 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
302 if (!ADS_ERR_OK(status)) {
303 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
306 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
308 if (!ADS_ERR_OK(status)) {
309 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
312 return ads_gen_mod(r->in.ads, r->out.dn, mods);
315 /****************************************************************
316 ****************************************************************/
318 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
319 struct libnet_JoinCtx *r)
324 if (!r->in.create_upn) {
329 status = libnet_join_connect_ads(mem_ctx, r);
330 if (!ADS_ERR_OK(status)) {
335 status = libnet_join_find_machine_acct(mem_ctx, r);
336 if (!ADS_ERR_OK(status)) {
341 r->in.upn = talloc_asprintf(mem_ctx,
344 r->out.dns_domain_name);
346 return ADS_ERROR(LDAP_NO_MEMORY);
350 mods = ads_init_mods(mem_ctx);
352 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
355 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
356 if (!ADS_ERR_OK(status)) {
357 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
360 return ads_gen_mod(r->in.ads, r->out.dn, mods);
364 /****************************************************************
365 ****************************************************************/
367 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
368 struct libnet_JoinCtx *r)
374 if (!r->in.os_name || !r->in.os_version ) {
379 status = libnet_join_connect_ads(mem_ctx, r);
380 if (!ADS_ERR_OK(status)) {
385 status = libnet_join_find_machine_acct(mem_ctx, r);
386 if (!ADS_ERR_OK(status)) {
390 mods = ads_init_mods(mem_ctx);
392 return ADS_ERROR(LDAP_NO_MEMORY);
395 os_sp = talloc_asprintf(mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
397 return ADS_ERROR(LDAP_NO_MEMORY);
400 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
402 if (!ADS_ERR_OK(status)) {
406 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
408 if (!ADS_ERR_OK(status)) {
412 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
414 if (!ADS_ERR_OK(status)) {
418 return ads_gen_mod(r->in.ads, r->out.dn, mods);
421 #endif /* HAVE_LDAP */
423 /****************************************************************
424 ****************************************************************/
426 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
427 struct libnet_JoinCtx *r)
429 if (!lp_use_kerberos_keytab()) {
433 if (!ads_keytab_create_default(r->in.ads)) {
436 #endif /* HAVE_KRB5 */
442 /****************************************************************
443 ****************************************************************/
445 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
446 struct libnet_JoinCtx *r)
448 uint32_t domain_func;
450 const char *salt = NULL;
451 char *std_salt = NULL;
453 status = ads_domain_func_level(r->in.ads, &domain_func);
454 if (!ADS_ERR_OK(status)) {
455 libnet_join_set_error_string(mem_ctx, r,
456 "Failed to determine domain functional level!\n");
460 std_salt = kerberos_standard_des_salt();
462 libnet_join_set_error_string(mem_ctx, r,
463 "failed to obtain standard DES salt\n");
467 salt = talloc_strdup(mem_ctx, std_salt);
474 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
477 upn = ads_get_upn(r->in.ads, mem_ctx,
480 salt = talloc_strdup(mem_ctx, upn);
487 return kerberos_secrets_store_des_salt(salt);
490 #endif /* HAVE_KRB5 */
492 /****************************************************************
493 ****************************************************************/
495 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
496 struct libnet_JoinCtx *r)
498 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
504 if (!secrets_store_machine_password(r->in.machine_password,
505 r->out.netbios_domain_name,
514 /****************************************************************
515 ****************************************************************/
517 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
518 struct libnet_JoinCtx *r)
520 struct cli_state *cli = NULL;
521 struct rpc_pipe_client *pipe_hnd = NULL;
522 POLICY_HND sam_pol, domain_pol, user_pol, lsa_pol;
523 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
525 const char *const_acct_name;
527 uint32 num_rids, *name_types, *user_rids;
528 uint32 flags = 0x3e8;
529 uint32 acb_info = ACB_WSTRUST;
530 uint32 fields_present;
532 SAM_USERINFO_CTR ctr;
533 SAM_USER_INFO_25 p25;
534 const int infolevel = 25;
535 struct MD5Context md5ctx;
537 DATA_BLOB digested_session_key;
538 uchar md4_trust_password[16];
540 if (!r->in.machine_password) {
541 r->in.machine_password = talloc_strdup(mem_ctx, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
542 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
545 status = cli_full_connection(&cli, NULL,
551 r->in.admin_password,
555 if (!NT_STATUS_IS_OK(status)) {
559 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
564 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
565 SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
566 if (!NT_STATUS_IS_OK(status)) {
570 status = rpccli_lsa_query_info_policy2(pipe_hnd, mem_ctx, &lsa_pol,
572 &r->out.netbios_domain_name,
573 &r->out.dns_domain_name,
578 if (!NT_STATUS_IS_OK(status)) {
579 status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &lsa_pol,
581 &r->out.netbios_domain_name,
583 if (!NT_STATUS_IS_OK(status)) {
588 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
589 cli_rpc_pipe_close(pipe_hnd);
591 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
596 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
597 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
598 if (!NT_STATUS_IS_OK(status)) {
602 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
603 SEC_RIGHTS_MAXIMUM_ALLOWED,
606 if (!NT_STATUS_IS_OK(status)) {
610 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
611 strlower_m(acct_name);
612 const_acct_name = acct_name;
614 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
615 status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx,
617 acct_name, ACB_WSTRUST,
618 0xe005000b, &user_pol,
620 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
621 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
626 if (NT_STATUS_IS_OK(status)) {
627 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
631 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
632 &domain_pol, flags, 1,
634 &num_rids, &user_rids, &name_types);
635 if (!NT_STATUS_IS_OK(status)) {
639 if (name_types[0] != SID_NAME_USER) {
640 status = NT_STATUS_INVALID_WORKSTATION;
644 user_rid = user_rids[0];
646 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
647 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
649 if (!NT_STATUS_IS_OK(status)) {
653 E_md4hash(r->in.machine_password, md4_trust_password);
654 encode_pw_buffer(pwbuf, r->in.machine_password, STR_UNICODE);
656 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
657 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
660 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
661 MD5Update(&md5ctx, cli->user_session_key.data,
662 cli->user_session_key.length);
663 MD5Final(digested_session_key.data, &md5ctx);
665 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
666 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
668 acb_info |= ACB_PWNOEXP;
670 if ( dom_type == ND_TYPE_AD ) {
671 #if !defined(ENCTYPE_ARCFOUR_HMAC)
672 acb_info |= ACB_USE_DES_KEY_ONLY;
680 fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
681 init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
683 ctr.switch_value = infolevel;
684 ctr.info.id25 = &p25;
686 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
687 infolevel, &cli->user_session_key,
689 if (!NT_STATUS_IS_OK(status)) {
693 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
694 cli_rpc_pipe_close(pipe_hnd);
696 status = NT_STATUS_OK;
705 /****************************************************************
706 ****************************************************************/
708 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
709 struct libnet_UnjoinCtx *r)
711 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
715 if (!secrets_delete_domain_sid(lp_workgroup())) {
722 /****************************************************************
723 ****************************************************************/
725 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
726 struct libnet_UnjoinCtx *r)
728 struct cli_state *cli = NULL;
729 struct rpc_pipe_client *pipe_hnd = NULL;
730 POLICY_HND sam_pol, domain_pol, user_pol;
731 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
733 uint32 flags = 0x3e8;
734 const char *const_acct_name;
736 uint32 num_rids, *name_types, *user_rids;
737 SAM_USERINFO_CTR ctr, *qctr = NULL;
738 SAM_USER_INFO_16 p16;
740 status = cli_full_connection(&cli, NULL,
746 r->in.admin_password,
749 if (!NT_STATUS_IS_OK(status)) {
753 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
758 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
759 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
760 if (!NT_STATUS_IS_OK(status)) {
764 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
765 SEC_RIGHTS_MAXIMUM_ALLOWED,
768 if (!NT_STATUS_IS_OK(status)) {
772 acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
773 strlower_m(acct_name);
774 const_acct_name = acct_name;
776 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
777 &domain_pol, flags, 1,
779 &num_rids, &user_rids, &name_types);
780 if (!NT_STATUS_IS_OK(status)) {
784 if (name_types[0] != SID_NAME_USER) {
785 status = NT_STATUS_INVALID_WORKSTATION;
789 user_rid = user_rids[0];
791 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
792 SEC_RIGHTS_MAXIMUM_ALLOWED,
793 user_rid, &user_pol);
794 if (!NT_STATUS_IS_OK(status)) {
798 status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx,
799 &user_pol, 16, &qctr);
800 if (!NT_STATUS_IS_OK(status)) {
801 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
806 ctr.switch_value = 16;
807 ctr.info.id16 = &p16;
809 p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
811 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
812 &cli->user_session_key, &ctr);
814 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
818 rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
819 rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
820 cli_rpc_pipe_close(pipe_hnd);
830 /****************************************************************
831 ****************************************************************/
833 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
838 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
840 werr = libnet_conf_set_global_parameter("security", "user");
841 W_ERROR_NOT_OK_RETURN(werr);
843 werr = libnet_conf_set_global_parameter("workgroup",
848 if (r->out.dns_domain_name) {
852 werr = libnet_conf_set_global_parameter("security", "domain");
853 W_ERROR_NOT_OK_RETURN(werr);
855 werr = libnet_conf_set_global_parameter("workgroup",
856 r->out.netbios_domain_name);
857 W_ERROR_NOT_OK_RETURN(werr);
860 werr = libnet_conf_set_global_parameter("security", "ads");
861 W_ERROR_NOT_OK_RETURN(werr);
863 werr = libnet_conf_set_global_parameter("realm",
864 r->out.dns_domain_name);
865 W_ERROR_NOT_OK_RETURN(werr);
871 /****************************************************************
872 ****************************************************************/
874 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
876 WERROR werr = WERR_OK;
878 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
880 werr = libnet_conf_set_global_parameter("security", "user");
881 W_ERROR_NOT_OK_RETURN(werr);
884 werr = libnet_conf_delete_parameter(GLOBAL_NAME, "realm");
889 /****************************************************************
890 ****************************************************************/
892 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
896 if (!W_ERROR_IS_OK(r->out.result)) {
897 return r->out.result;
900 if (!r->in.modify_config) {
904 werr = do_join_modify_vals_config(r);
905 if (!W_ERROR_IS_OK(werr)) {
909 r->out.modified_config = true;
910 r->out.result = werr;
915 /****************************************************************
916 ****************************************************************/
918 static WERROR do_UnjoinConfig(struct libnet_UnjoinCtx *r)
922 if (!W_ERROR_IS_OK(r->out.result)) {
923 return r->out.result;
926 if (!r->in.modify_config) {
930 werr = do_unjoin_modify_vals_config(r);
931 if (!W_ERROR_IS_OK(werr)) {
935 r->out.modified_config = true;
936 r->out.result = werr;
941 /****************************************************************
942 ****************************************************************/
944 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
947 ads_destroy(&r->in.ads);
953 /****************************************************************
954 ****************************************************************/
956 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
959 ads_destroy(&r->in.ads);
965 /****************************************************************
966 ****************************************************************/
968 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
969 struct libnet_JoinCtx **r)
971 struct libnet_JoinCtx *ctx;
973 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
978 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
980 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
981 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
988 /****************************************************************
989 ****************************************************************/
991 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
992 struct libnet_UnjoinCtx **r)
994 struct libnet_UnjoinCtx *ctx;
996 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1001 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1003 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1004 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1011 /****************************************************************
1012 ****************************************************************/
1014 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1015 struct libnet_JoinCtx *r)
1019 ADS_STATUS ads_status;
1021 if (r->in.account_ou) {
1022 ads_status = libnet_join_connect_ads(mem_ctx, r);
1023 if (!ADS_ERR_OK(ads_status)) {
1024 return WERR_GENERAL_FAILURE;
1026 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1027 if (!ADS_ERR_OK(ads_status)) {
1028 libnet_join_set_error_string(mem_ctx, r,
1029 "failed to precreate account in ou %s: %s\n",
1031 ads_errstr(ads_status));
1032 return WERR_GENERAL_FAILURE;
1035 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1037 #endif /* HAVE_LDAP */
1038 status = libnet_join_joindomain_rpc(mem_ctx, r);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1041 return WERR_SETUP_ALREADY_JOINED;
1043 return ntstatus_to_werror(status);
1046 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1047 return WERR_SETUP_NOT_JOINED;
1051 ads_status = libnet_join_set_machine_spn(mem_ctx, r);
1052 if (!ADS_ERR_OK(ads_status)) {
1053 libnet_join_set_error_string(mem_ctx, r,
1054 "failed to set machine spn: %s\n",
1055 ads_errstr(ads_status));
1056 return WERR_GENERAL_FAILURE;
1059 ads_status = libnet_join_set_os_attributes(mem_ctx, r);
1060 if (!ADS_ERR_OK(ads_status)) {
1061 libnet_join_set_error_string(mem_ctx, r,
1062 "failed to set machine os attributes: %s\n",
1063 ads_errstr(ads_status));
1064 return WERR_GENERAL_FAILURE;
1067 ads_status = libnet_join_set_machine_upn(mem_ctx, r);
1068 if (!ADS_ERR_OK(ads_status)) {
1069 libnet_join_set_error_string(mem_ctx, r,
1070 "failed to set machine upn: %s\n",
1071 ads_errstr(ads_status));
1072 return WERR_GENERAL_FAILURE;
1076 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
1077 return WERR_GENERAL_FAILURE;
1079 #endif /* HAVE_KRB5 */
1081 #endif /* HAVE_LDAP */
1082 if (!libnet_join_create_keytab(mem_ctx, r)) {
1083 libnet_join_set_error_string(mem_ctx, r,
1084 "failed to create kerberos keytab\n");
1085 return WERR_GENERAL_FAILURE;
1091 /****************************************************************
1092 ****************************************************************/
1094 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1095 struct libnet_JoinCtx *r)
1099 if (!r->in.domain_name) {
1100 return WERR_INVALID_PARAM;
1103 if (r->in.modify_config && !lp_include_registry_globals()) {
1104 return WERR_NOT_SUPPORTED;
1108 return WERR_SETUP_DOMAIN_CONTROLLER;
1111 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1112 werr = libnet_DomainJoin(mem_ctx, r);
1113 if (!W_ERROR_IS_OK(werr)) {
1118 werr = do_JoinConfig(r);
1119 if (!W_ERROR_IS_OK(werr)) {
1126 /****************************************************************
1127 ****************************************************************/
1129 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1130 struct libnet_UnjoinCtx *r)
1134 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
1135 if (!NT_STATUS_IS_OK(status)) {
1136 libnet_unjoin_set_error_string(mem_ctx, r,
1137 "failed to unjoin domain: %s\n",
1139 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1140 return WERR_SETUP_NOT_JOINED;
1142 return ntstatus_to_werror(status);
1146 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
1147 ADS_STATUS ads_status;
1148 libnet_unjoin_connect_ads(mem_ctx, r);
1149 ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
1150 if (!ADS_ERR_OK(ads_status)) {
1151 libnet_unjoin_set_error_string(mem_ctx, r,
1152 "failed to remove machine account from AD: %s\n",
1153 ads_errstr(ads_status));
1156 #endif /* HAVE_LDAP */
1157 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
1162 /****************************************************************
1163 ****************************************************************/
1165 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
1166 struct libnet_UnjoinCtx *r)
1170 if (r->in.modify_config && !lp_include_registry_globals()) {
1171 return WERR_NOT_SUPPORTED;
1174 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1175 werr = libnet_DomainUnjoin(mem_ctx, r);
1176 if (!W_ERROR_IS_OK(werr)) {
1182 werr = do_UnjoinConfig(r);
1183 if (!W_ERROR_IS_OK(werr)) {