For libnet_join error string functions, make sure not to overwrite last status string.
[Samba/gebeck_regimport.git] / source / libnet / libnet_join.c
blobfbbbb51bbc24960f108d8848851b047f8a7e073a
1 /*
2 * Unix SMB/CIFS implementation.
3 * libnet Join Support
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/>.
21 #include "includes.h"
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, ...)
32 va_list args;
34 if (r->out.error_string) {
35 return;
38 va_start(args, format);
39 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
40 va_end(args);
43 /****************************************************************
44 ****************************************************************/
46 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
47 struct libnet_UnjoinCtx *r,
48 const char *format, ...)
50 va_list args;
52 if (r->out.error_string) {
53 return;
56 va_start(args, format);
57 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
58 va_end(args);
61 #ifdef WITH_ADS
63 /****************************************************************
64 ****************************************************************/
66 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
67 const char *netbios_domain_name,
68 const char *dc_name,
69 const char *user_name,
70 const char *password,
71 ADS_STRUCT **ads)
73 ADS_STATUS status;
74 ADS_STRUCT *my_ads = NULL;
76 my_ads = ads_init(dns_domain_name,
77 netbios_domain_name,
78 dc_name);
79 if (!my_ads) {
80 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
83 if (user_name) {
84 SAFE_FREE(my_ads->auth.user_name);
85 my_ads->auth.user_name = SMB_STRDUP(user_name);
88 if (password) {
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)) {
95 ads_destroy(&my_ads);
96 return status;
99 *ads = my_ads;
100 return ADS_SUCCESS;
103 /****************************************************************
104 ****************************************************************/
106 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
107 struct libnet_JoinCtx *r)
109 ADS_STATUS status;
111 if (r->in.ads) {
112 ads_destroy(&r->in.ads);
115 status = libnet_connect_ads(r->in.domain_name,
116 r->in.domain_name,
117 r->in.dc_name,
118 r->in.admin_account,
119 r->in.admin_password,
120 &r->in.ads);
121 if (!ADS_ERR_OK(status)) {
122 libnet_join_set_error_string(mem_ctx, r,
123 "failed to connect to AD: %s",
124 ads_errstr(status));
127 return status;
130 /****************************************************************
131 ****************************************************************/
133 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
134 struct libnet_UnjoinCtx *r)
136 ADS_STATUS status;
138 if (r->in.ads) {
139 ads_destroy(&r->in.ads);
142 status = libnet_connect_ads(r->in.domain_name,
143 r->in.domain_name,
144 r->in.dc_name,
145 r->in.admin_account,
146 r->in.admin_password,
147 &r->in.ads);
148 if (!ADS_ERR_OK(status)) {
149 libnet_unjoin_set_error_string(mem_ctx, r,
150 "failed to connect to AD: %s",
151 ads_errstr(status));
154 return status;
157 /****************************************************************
158 ****************************************************************/
160 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
161 struct libnet_JoinCtx *r)
163 ADS_STATUS status;
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)) {
169 return 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,
178 r->in.machine_name,
179 r->in.account_ou);
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;
187 return status;
190 /****************************************************************
191 ****************************************************************/
193 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
194 struct libnet_UnjoinCtx *r)
196 ADS_STATUS status;
198 if (!r->in.ads) {
199 status = libnet_unjoin_connect_ads(mem_ctx, r);
200 if (!ADS_ERR_OK(status)) {
201 return 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",
209 ads_errstr(status));
210 return status;
213 return ADS_SUCCESS;
216 /****************************************************************
217 ****************************************************************/
219 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
220 struct libnet_JoinCtx *r)
222 ADS_STATUS status;
223 LDAPMessage *res = NULL;
224 char *dn = NULL;
226 if (!r->in.machine_name) {
227 return ADS_ERROR(LDAP_NO_MEMORY);
230 status = ads_find_machine_acct(r->in.ads,
231 &res,
232 r->in.machine_name);
233 if (!ADS_ERR_OK(status)) {
234 return status;
237 if (ads_count_replies(r->in.ads, res) != 1) {
238 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
239 goto done;
242 dn = ads_get_dn(r->in.ads, res);
243 if (!dn) {
244 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
245 goto done;
248 TALLOC_FREE(r->out.dn);
249 r->out.dn = talloc_strdup(mem_ctx, dn);
250 if (!r->out.dn) {
251 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
252 goto done;
255 done:
256 ads_msgfree(r->in.ads, res);
257 ads_memfree(r->in.ads, dn);
259 return status;
262 /****************************************************************
263 ****************************************************************/
265 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
266 struct libnet_JoinCtx *r)
268 ADS_STATUS status;
269 ADS_MODLIST mods;
270 fstring my_fqdn;
271 const char *spn_array[3] = {NULL, NULL, NULL};
272 char *spn = NULL;
274 if (!r->in.ads) {
275 status = libnet_join_connect_ads(mem_ctx, r);
276 if (!ADS_ERR_OK(status)) {
277 return status;
281 status = libnet_join_find_machine_acct(mem_ctx, r);
282 if (!ADS_ERR_OK(status)) {
283 return status;
286 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
287 if (!spn) {
288 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
290 strupper_m(spn);
291 spn_array[0] = spn;
293 if (name_to_fqdn(my_fqdn, r->in.machine_name) &&
294 !strequal(my_fqdn, r->in.machine_name)) {
296 strlower_m(my_fqdn);
297 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
298 if (!spn) {
299 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
301 spn_array[1] = spn;
304 mods = ads_init_mods(mem_ctx);
305 if (!mods) {
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",
315 spn_array);
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)
329 ADS_STATUS status;
330 ADS_MODLIST mods;
332 if (!r->in.create_upn) {
333 return ADS_SUCCESS;
336 if (!r->in.ads) {
337 status = libnet_join_connect_ads(mem_ctx, r);
338 if (!ADS_ERR_OK(status)) {
339 return status;
343 status = libnet_join_find_machine_acct(mem_ctx, r);
344 if (!ADS_ERR_OK(status)) {
345 return status;
348 if (!r->in.upn) {
349 r->in.upn = talloc_asprintf(mem_ctx,
350 "host/%s@%s",
351 r->in.machine_name,
352 r->out.dns_domain_name);
353 if (!r->in.upn) {
354 return ADS_ERROR(LDAP_NO_MEMORY);
358 mods = ads_init_mods(mem_ctx);
359 if (!mods) {
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)
378 ADS_STATUS status;
379 ADS_MODLIST mods;
380 char *os_sp = NULL;
382 if (!r->in.os_name || !r->in.os_version ) {
383 return ADS_SUCCESS;
386 if (!r->in.ads) {
387 status = libnet_join_connect_ads(mem_ctx, r);
388 if (!ADS_ERR_OK(status)) {
389 return status;
393 status = libnet_join_find_machine_acct(mem_ctx, r);
394 if (!ADS_ERR_OK(status)) {
395 return status;
398 mods = ads_init_mods(mem_ctx);
399 if (!mods) {
400 return ADS_ERROR(LDAP_NO_MEMORY);
403 os_sp = talloc_asprintf(mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
404 if (!os_sp) {
405 return ADS_ERROR(LDAP_NO_MEMORY);
408 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
409 r->in.os_name);
410 if (!ADS_ERR_OK(status)) {
411 return status;
414 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
415 r->in.os_version);
416 if (!ADS_ERR_OK(status)) {
417 return status;
420 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
421 os_sp);
422 if (!ADS_ERR_OK(status)) {
423 return 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()) {
436 return true;
439 if (!ads_keytab_create_default(r->in.ads)) {
440 return false;
443 return true;
446 /****************************************************************
447 ****************************************************************/
449 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
450 struct libnet_JoinCtx *r)
452 uint32_t domain_func;
453 ADS_STATUS status;
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!");
461 return false;
464 std_salt = kerberos_standard_des_salt();
465 if (!std_salt) {
466 libnet_join_set_error_string(mem_ctx, r,
467 "failed to obtain standard DES salt");
468 return false;
471 salt = talloc_strdup(mem_ctx, std_salt);
472 if (!salt) {
473 return false;
476 SAFE_FREE(std_salt);
478 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
479 char *upn;
481 upn = ads_get_upn(r->in.ads, mem_ctx,
482 r->in.machine_name);
483 if (upn) {
484 salt = talloc_strdup(mem_ctx, upn);
485 if (!salt) {
486 return false;
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)
500 ADS_STATUS status;
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",
506 ads_errstr(status));
507 return status;
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",
514 ads_errstr(status));
515 return status;
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",
522 ads_errstr(status));
523 return status;
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);
536 return ADS_SUCCESS;
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,
547 r->out.domain_sid))
549 return false;
552 if (!secrets_store_machine_password(r->in.machine_password,
553 r->out.netbios_domain_name,
554 SEC_CHAN_WKSTA))
556 return false;
559 return true;
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;
572 char *acct_name;
573 const char *const_acct_name;
574 uint32 user_rid;
575 uint32 num_rids, *name_types, *user_rids;
576 uint32 flags = 0x3e8;
577 uint32 acb_info = ACB_WSTRUST;
578 uint32 fields_present;
579 uchar pwbuf[532];
580 SAM_USERINFO_CTR ctr;
581 SAM_USER_INFO_25 p25;
582 const int infolevel = 25;
583 struct MD5Context md5ctx;
584 uchar md5buffer[16];
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,
594 r->in.dc_name,
595 NULL, 0,
596 "IPC$", "IPC",
597 r->in.admin_account,
598 NULL,
599 r->in.admin_password,
601 Undefined, NULL);
603 if (!NT_STATUS_IS_OK(status)) {
604 goto done;
607 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
608 if (!pipe_hnd) {
609 goto done;
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)) {
615 goto done;
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,
622 NULL,
623 NULL,
624 &r->out.domain_sid);
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,
634 &r->out.domain_sid);
635 if (!NT_STATUS_IS_OK(status)) {
636 goto done;
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);
644 if (!pipe_hnd) {
645 goto done;
648 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
649 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
650 if (!NT_STATUS_IS_OK(status)) {
651 goto done;
654 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
655 SEC_RIGHTS_MAXIMUM_ALLOWED,
656 r->out.domain_sid,
657 &domain_pol);
658 if (!NT_STATUS_IS_OK(status)) {
659 goto done;
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,
668 &domain_pol,
669 acct_name, ACB_WSTRUST,
670 0xe005000b, &user_pol,
671 &user_rid);
672 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
673 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
674 goto done;
678 if (NT_STATUS_IS_OK(status)) {
679 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
683 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
684 &domain_pol, flags, 1,
685 &const_acct_name,
686 &num_rids, &user_rids, &name_types);
687 if (!NT_STATUS_IS_OK(status)) {
688 goto done;
691 if (name_types[0] != SID_NAME_USER) {
692 status = NT_STATUS_INVALID_WORKSTATION;
693 goto done;
696 user_rid = user_rids[0];
698 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
699 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
700 &user_pol);
701 if (!NT_STATUS_IS_OK(status)) {
702 goto done;
705 E_md4hash(r->in.machine_password, md4_trust_password);
706 encode_pw_buffer(pwbuf, r->in.machine_password, STR_UNICODE);
708 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
709 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
711 MD5Init(&md5ctx);
712 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
713 MD5Update(&md5ctx, cli->user_session_key.data,
714 cli->user_session_key.length);
715 MD5Final(digested_session_key.data, &md5ctx);
717 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
718 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
720 acb_info |= ACB_PWNOEXP;
721 if (r->out.domain_is_ad) {
722 #if !defined(ENCTYPE_ARCFOUR_HMAC)
723 acb_info |= ACB_USE_DES_KEY_ONLY;
724 #endif
728 ZERO_STRUCT(ctr);
729 ZERO_STRUCT(p25);
731 fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS;
732 init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf);
734 ctr.switch_value = infolevel;
735 ctr.info.id25 = &p25;
737 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol,
738 infolevel, &cli->user_session_key,
739 &ctr);
740 if (!NT_STATUS_IS_OK(status)) {
741 goto done;
744 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
745 cli_rpc_pipe_close(pipe_hnd);
747 status = NT_STATUS_OK;
748 done:
749 if (cli) {
750 cli_shutdown(cli);
753 return status;
756 /****************************************************************
757 ****************************************************************/
759 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
760 struct libnet_UnjoinCtx *r)
762 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
763 return false;
766 if (!secrets_delete_domain_sid(lp_workgroup())) {
767 return false;
770 return true;
773 /****************************************************************
774 ****************************************************************/
776 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
777 struct libnet_UnjoinCtx *r)
779 struct cli_state *cli = NULL;
780 struct rpc_pipe_client *pipe_hnd = NULL;
781 POLICY_HND sam_pol, domain_pol, user_pol;
782 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
783 char *acct_name;
784 uint32 flags = 0x3e8;
785 const char *const_acct_name;
786 uint32 user_rid;
787 uint32 num_rids, *name_types, *user_rids;
788 SAM_USERINFO_CTR ctr, *qctr = NULL;
789 SAM_USER_INFO_16 p16;
791 status = cli_full_connection(&cli, NULL,
792 r->in.dc_name,
793 NULL, 0,
794 "IPC$", "IPC",
795 r->in.admin_account,
796 NULL,
797 r->in.admin_password,
798 0, Undefined, NULL);
800 if (!NT_STATUS_IS_OK(status)) {
801 goto done;
804 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
805 if (!pipe_hnd) {
806 goto done;
809 status = rpccli_samr_connect(pipe_hnd, mem_ctx,
810 SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
811 if (!NT_STATUS_IS_OK(status)) {
812 goto done;
815 status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
816 SEC_RIGHTS_MAXIMUM_ALLOWED,
817 r->in.domain_sid,
818 &domain_pol);
819 if (!NT_STATUS_IS_OK(status)) {
820 goto done;
823 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
824 strlower_m(acct_name);
825 const_acct_name = acct_name;
827 status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
828 &domain_pol, flags, 1,
829 &const_acct_name,
830 &num_rids, &user_rids, &name_types);
831 if (!NT_STATUS_IS_OK(status)) {
832 goto done;
835 if (name_types[0] != SID_NAME_USER) {
836 status = NT_STATUS_INVALID_WORKSTATION;
837 goto done;
840 user_rid = user_rids[0];
842 status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
843 SEC_RIGHTS_MAXIMUM_ALLOWED,
844 user_rid, &user_pol);
845 if (!NT_STATUS_IS_OK(status)) {
846 goto done;
849 status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx,
850 &user_pol, 16, &qctr);
851 if (!NT_STATUS_IS_OK(status)) {
852 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
853 goto done;
856 ZERO_STRUCT(ctr);
857 ctr.switch_value = 16;
858 ctr.info.id16 = &p16;
860 p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
862 status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
863 &cli->user_session_key, &ctr);
865 rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
867 done:
868 if (pipe_hnd) {
869 rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
870 rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
871 cli_rpc_pipe_close(pipe_hnd);
874 if (cli) {
875 cli_shutdown(cli);
878 return status;
881 /****************************************************************
882 ****************************************************************/
884 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
886 WERROR werr;
888 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
890 werr = libnet_conf_set_global_parameter("security", "user");
891 W_ERROR_NOT_OK_RETURN(werr);
893 werr = libnet_conf_set_global_parameter("workgroup",
894 r->in.domain_name);
895 return werr;
898 werr = libnet_conf_set_global_parameter("security", "domain");
899 W_ERROR_NOT_OK_RETURN(werr);
901 werr = libnet_conf_set_global_parameter("workgroup",
902 r->out.netbios_domain_name);
903 W_ERROR_NOT_OK_RETURN(werr);
905 if (r->out.domain_is_ad) {
906 werr = libnet_conf_set_global_parameter("security", "ads");
907 W_ERROR_NOT_OK_RETURN(werr);
909 werr = libnet_conf_set_global_parameter("realm",
910 r->out.dns_domain_name);
911 W_ERROR_NOT_OK_RETURN(werr);
914 return werr;
917 /****************************************************************
918 ****************************************************************/
920 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
922 WERROR werr = WERR_OK;
924 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
926 werr = libnet_conf_set_global_parameter("security", "user");
927 W_ERROR_NOT_OK_RETURN(werr);
930 libnet_conf_delete_parameter(GLOBAL_NAME, "realm");
932 return werr;
935 /****************************************************************
936 ****************************************************************/
938 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
940 WERROR werr;
942 if (!W_ERROR_IS_OK(r->out.result)) {
943 return r->out.result;
946 if (!r->in.modify_config) {
947 return WERR_OK;
950 werr = do_join_modify_vals_config(r);
951 if (!W_ERROR_IS_OK(werr)) {
952 return werr;
955 r->out.modified_config = true;
956 r->out.result = werr;
958 return werr;
961 /****************************************************************
962 ****************************************************************/
964 static WERROR do_UnjoinConfig(struct libnet_UnjoinCtx *r)
966 WERROR werr;
968 if (!W_ERROR_IS_OK(r->out.result)) {
969 return r->out.result;
972 if (!r->in.modify_config) {
973 return WERR_OK;
976 werr = do_unjoin_modify_vals_config(r);
977 if (!W_ERROR_IS_OK(werr)) {
978 return werr;
981 r->out.modified_config = true;
982 r->out.result = werr;
984 return werr;
987 /****************************************************************
988 ****************************************************************/
990 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
992 if (r->in.ads) {
993 ads_destroy(&r->in.ads);
996 return 0;
999 /****************************************************************
1000 ****************************************************************/
1002 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1004 if (r->in.ads) {
1005 ads_destroy(&r->in.ads);
1008 return 0;
1011 /****************************************************************
1012 ****************************************************************/
1014 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1015 struct libnet_JoinCtx **r)
1017 struct libnet_JoinCtx *ctx;
1019 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1020 if (!ctx) {
1021 return WERR_NOMEM;
1024 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1026 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1027 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1029 *r = ctx;
1031 return WERR_OK;
1034 /****************************************************************
1035 ****************************************************************/
1037 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1038 struct libnet_UnjoinCtx **r)
1040 struct libnet_UnjoinCtx *ctx;
1042 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1043 if (!ctx) {
1044 return WERR_NOMEM;
1047 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1049 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1050 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1052 *r = ctx;
1054 return WERR_OK;
1057 /****************************************************************
1058 ****************************************************************/
1060 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1061 struct libnet_JoinCtx *r)
1063 NTSTATUS status;
1064 #ifdef WITH_ADS
1065 ADS_STATUS ads_status;
1067 if (r->in.account_ou) {
1068 ads_status = libnet_join_connect_ads(mem_ctx, r);
1069 if (!ADS_ERR_OK(ads_status)) {
1070 return WERR_GENERAL_FAILURE;
1072 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1073 if (!ADS_ERR_OK(ads_status)) {
1074 libnet_join_set_error_string(mem_ctx, r,
1075 "failed to precreate account in ou %s: %s",
1076 r->in.account_ou,
1077 ads_errstr(ads_status));
1078 return WERR_GENERAL_FAILURE;
1081 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1083 #endif /* WITH_ADS */
1084 status = libnet_join_joindomain_rpc(mem_ctx, r);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1087 return WERR_SETUP_ALREADY_JOINED;
1089 return ntstatus_to_werror(status);
1092 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1093 return WERR_SETUP_NOT_JOINED;
1096 #ifdef WITH_ADS
1097 if (r->out.domain_is_ad) {
1098 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1099 if (!ADS_ERR_OK(ads_status)) {
1100 return WERR_GENERAL_FAILURE;
1103 #endif /* WITH_ADS */
1105 return WERR_OK;
1108 /****************************************************************
1109 ****************************************************************/
1111 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1112 struct libnet_JoinCtx *r)
1114 WERROR werr;
1116 if (!r->in.domain_name) {
1117 return WERR_INVALID_PARAM;
1120 if (r->in.modify_config && !lp_include_registry_globals()) {
1121 return WERR_NOT_SUPPORTED;
1124 if (IS_DC) {
1125 return WERR_SETUP_DOMAIN_CONTROLLER;
1128 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1129 werr = libnet_DomainJoin(mem_ctx, r);
1130 if (!W_ERROR_IS_OK(werr)) {
1131 return werr;
1135 werr = do_JoinConfig(r);
1136 if (!W_ERROR_IS_OK(werr)) {
1137 return werr;
1140 return werr;
1143 /****************************************************************
1144 ****************************************************************/
1146 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1147 struct libnet_UnjoinCtx *r)
1149 NTSTATUS status;
1151 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
1152 if (!NT_STATUS_IS_OK(status)) {
1153 libnet_unjoin_set_error_string(mem_ctx, r,
1154 "failed to unjoin domain: %s",
1155 nt_errstr(status));
1156 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1157 return WERR_SETUP_NOT_JOINED;
1159 return ntstatus_to_werror(status);
1162 #ifdef WITH_ADS
1163 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
1164 ADS_STATUS ads_status;
1165 libnet_unjoin_connect_ads(mem_ctx, r);
1166 ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
1167 if (!ADS_ERR_OK(ads_status)) {
1168 libnet_unjoin_set_error_string(mem_ctx, r,
1169 "failed to remove machine account from AD: %s",
1170 ads_errstr(ads_status));
1173 #endif /* WITH_ADS */
1175 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
1177 return WERR_OK;
1180 /****************************************************************
1181 ****************************************************************/
1183 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
1184 struct libnet_UnjoinCtx *r)
1186 WERROR werr;
1188 if (r->in.modify_config && !lp_include_registry_globals()) {
1189 return WERR_NOT_SUPPORTED;
1192 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1193 werr = libnet_DomainUnjoin(mem_ctx, r);
1194 if (!W_ERROR_IS_OK(werr)) {
1195 do_UnjoinConfig(r);
1196 return werr;
1200 werr = do_UnjoinConfig(r);
1201 if (!W_ERROR_IS_OK(werr)) {
1202 return werr;
1205 return werr;