s3:vfs:gpfs: fix flapping offline: always get winAttrs from gpfs for is_offline
[Samba.git] / source3 / libnet / libnet_join.c
blobfe348d1b532113d96d5a7da6c87e1f88d890e47e
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 "ads.h"
23 #include "librpc/gen_ndr/ndr_libnet_join.h"
24 #include "libnet/libnet_join.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/ndr_samr_c.h"
27 #include "rpc_client/init_samr.h"
28 #include "../librpc/gen_ndr/ndr_lsa_c.h"
29 #include "rpc_client/cli_lsarpc.h"
30 #include "../librpc/gen_ndr/ndr_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
32 #include "lib/smbconf/smbconf.h"
33 #include "lib/smbconf/smbconf_reg.h"
34 #include "../libds/common/flags.h"
35 #include "secrets.h"
36 #include "rpc_client/init_lsa.h"
37 #include "rpc_client/cli_pipe.h"
38 #include "../libcli/security/security.h"
39 #include "passdb.h"
40 #include "libsmb/libsmb.h"
41 #include "../libcli/smb/smbXcli_base.h"
42 #include "lib/param/loadparm.h"
43 #include "libcli/auth/netlogon_creds_cli.h"
44 #include "auth/credentials/credentials.h"
46 /****************************************************************
47 ****************************************************************/
49 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
50 do { \
51 char *str = NULL; \
52 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
53 DEBUG(1,("libnet_Join:\n%s", str)); \
54 TALLOC_FREE(str); \
55 } while (0)
57 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
58 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
59 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
60 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
62 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
63 do { \
64 char *str = NULL; \
65 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
66 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
67 TALLOC_FREE(str); \
68 } while (0)
70 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
71 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
72 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
73 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
75 /****************************************************************
76 ****************************************************************/
78 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
79 struct libnet_JoinCtx *r,
80 const char *format, ...)
82 va_list args;
84 if (r->out.error_string) {
85 return;
88 va_start(args, format);
89 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
90 va_end(args);
93 /****************************************************************
94 ****************************************************************/
96 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
97 struct libnet_UnjoinCtx *r,
98 const char *format, ...)
100 va_list args;
102 if (r->out.error_string) {
103 return;
106 va_start(args, format);
107 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
108 va_end(args);
111 #ifdef HAVE_ADS
113 /****************************************************************
114 ****************************************************************/
116 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
117 const char *netbios_domain_name,
118 const char *dc_name,
119 const char *user_name,
120 const char *password,
121 ADS_STRUCT **ads)
123 ADS_STATUS status;
124 ADS_STRUCT *my_ads = NULL;
125 char *cp;
127 my_ads = ads_init(dns_domain_name,
128 netbios_domain_name,
129 dc_name);
130 if (!my_ads) {
131 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
134 if (user_name) {
135 SAFE_FREE(my_ads->auth.user_name);
136 my_ads->auth.user_name = SMB_STRDUP(user_name);
137 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
138 *cp++ = '\0';
139 SAFE_FREE(my_ads->auth.realm);
140 my_ads->auth.realm = smb_xstrdup(cp);
141 if (!strupper_m(my_ads->auth.realm)) {
142 ads_destroy(&my_ads);
143 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
148 if (password) {
149 SAFE_FREE(my_ads->auth.password);
150 my_ads->auth.password = SMB_STRDUP(password);
153 status = ads_connect_user_creds(my_ads);
154 if (!ADS_ERR_OK(status)) {
155 ads_destroy(&my_ads);
156 return status;
159 *ads = my_ads;
160 return ADS_SUCCESS;
163 /****************************************************************
164 ****************************************************************/
166 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
167 struct libnet_JoinCtx *r)
169 ADS_STATUS status;
171 status = libnet_connect_ads(r->out.dns_domain_name,
172 r->out.netbios_domain_name,
173 r->in.dc_name,
174 r->in.admin_account,
175 r->in.admin_password,
176 &r->in.ads);
177 if (!ADS_ERR_OK(status)) {
178 libnet_join_set_error_string(mem_ctx, r,
179 "failed to connect to AD: %s",
180 ads_errstr(status));
181 return status;
184 if (!r->out.netbios_domain_name) {
185 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
186 r->in.ads->server.workgroup);
187 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
190 if (!r->out.dns_domain_name) {
191 r->out.dns_domain_name = talloc_strdup(mem_ctx,
192 r->in.ads->config.realm);
193 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
196 r->out.domain_is_ad = true;
198 return ADS_SUCCESS;
201 /****************************************************************
202 ****************************************************************/
204 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
205 struct libnet_UnjoinCtx *r)
207 ADS_STATUS status;
209 status = libnet_connect_ads(r->in.domain_name,
210 r->in.domain_name,
211 r->in.dc_name,
212 r->in.admin_account,
213 r->in.admin_password,
214 &r->in.ads);
215 if (!ADS_ERR_OK(status)) {
216 libnet_unjoin_set_error_string(mem_ctx, r,
217 "failed to connect to AD: %s",
218 ads_errstr(status));
221 return status;
224 /****************************************************************
225 join a domain using ADS (LDAP mods)
226 ****************************************************************/
228 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
229 struct libnet_JoinCtx *r)
231 ADS_STATUS status;
232 LDAPMessage *res = NULL;
233 const char *attrs[] = { "dn", NULL };
234 bool moved = false;
236 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
237 if (!ADS_ERR_OK(status)) {
238 return status;
241 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
242 if (!ADS_ERR_OK(status)) {
243 return status;
246 if (ads_count_replies(r->in.ads, res) != 1) {
247 ads_msgfree(r->in.ads, res);
248 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
251 ads_msgfree(r->in.ads, res);
253 /* Attempt to create the machine account and bail if this fails.
254 Assume that the admin wants exactly what they requested */
256 status = ads_create_machine_acct(r->in.ads,
257 r->in.machine_name,
258 r->in.account_ou);
260 if (ADS_ERR_OK(status)) {
261 DEBUG(1,("machine account creation created\n"));
262 return status;
263 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
264 (status.err.rc == LDAP_ALREADY_EXISTS)) {
265 status = ADS_SUCCESS;
268 if (!ADS_ERR_OK(status)) {
269 DEBUG(1,("machine account creation failed\n"));
270 return status;
273 status = ads_move_machine_acct(r->in.ads,
274 r->in.machine_name,
275 r->in.account_ou,
276 &moved);
277 if (!ADS_ERR_OK(status)) {
278 DEBUG(1,("failure to locate/move pre-existing "
279 "machine account\n"));
280 return status;
283 DEBUG(1,("The machine account %s the specified OU.\n",
284 moved ? "was moved into" : "already exists in"));
286 return status;
289 /****************************************************************
290 ****************************************************************/
292 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
293 struct libnet_UnjoinCtx *r)
295 ADS_STATUS status;
297 if (!r->in.ads) {
298 status = libnet_unjoin_connect_ads(mem_ctx, r);
299 if (!ADS_ERR_OK(status)) {
300 libnet_unjoin_set_error_string(mem_ctx, r,
301 "failed to connect to AD: %s",
302 ads_errstr(status));
303 return status;
307 status = ads_leave_realm(r->in.ads, r->in.machine_name);
308 if (!ADS_ERR_OK(status)) {
309 libnet_unjoin_set_error_string(mem_ctx, r,
310 "failed to leave realm: %s",
311 ads_errstr(status));
312 return status;
315 return ADS_SUCCESS;
318 /****************************************************************
319 ****************************************************************/
321 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
322 struct libnet_JoinCtx *r)
324 ADS_STATUS status;
325 LDAPMessage *res = NULL;
326 char *dn = NULL;
328 if (!r->in.machine_name) {
329 return ADS_ERROR(LDAP_NO_MEMORY);
332 status = ads_find_machine_acct(r->in.ads,
333 &res,
334 r->in.machine_name);
335 if (!ADS_ERR_OK(status)) {
336 return status;
339 if (ads_count_replies(r->in.ads, res) != 1) {
340 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
341 goto done;
344 dn = ads_get_dn(r->in.ads, mem_ctx, res);
345 if (!dn) {
346 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
347 goto done;
350 r->out.dn = talloc_strdup(mem_ctx, dn);
351 if (!r->out.dn) {
352 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
353 goto done;
356 done:
357 ads_msgfree(r->in.ads, res);
358 TALLOC_FREE(dn);
360 return status;
363 /****************************************************************
364 Set a machines dNSHostName and servicePrincipalName attributes
365 ****************************************************************/
367 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
368 struct libnet_JoinCtx *r)
370 ADS_STATUS status;
371 ADS_MODLIST mods;
372 fstring my_fqdn;
373 const char *spn_array[3] = {NULL, NULL, NULL};
374 char *spn = NULL;
376 /* Find our DN */
378 status = libnet_join_find_machine_acct(mem_ctx, r);
379 if (!ADS_ERR_OK(status)) {
380 return status;
383 /* Windows only creates HOST/shortname & HOST/fqdn. */
385 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
386 if (!spn) {
387 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
389 if (!strupper_m(spn)) {
390 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
392 spn_array[0] = spn;
394 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
395 || (strchr(my_fqdn, '.') == NULL)) {
396 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
397 r->out.dns_domain_name);
400 if (!strlower_m(my_fqdn)) {
401 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
404 if (!strequal(my_fqdn, r->in.machine_name)) {
405 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
406 if (!spn) {
407 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
409 spn_array[1] = spn;
412 mods = ads_init_mods(mem_ctx);
413 if (!mods) {
414 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
417 /* fields of primary importance */
419 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
420 if (!ADS_ERR_OK(status)) {
421 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
424 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
425 spn_array);
426 if (!ADS_ERR_OK(status)) {
427 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
430 return ads_gen_mod(r->in.ads, r->out.dn, mods);
433 /****************************************************************
434 ****************************************************************/
436 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
437 struct libnet_JoinCtx *r)
439 ADS_STATUS status;
440 ADS_MODLIST mods;
442 if (!r->in.create_upn) {
443 return ADS_SUCCESS;
446 /* Find our DN */
448 status = libnet_join_find_machine_acct(mem_ctx, r);
449 if (!ADS_ERR_OK(status)) {
450 return status;
453 if (!r->in.upn) {
454 const char *realm = r->out.dns_domain_name;
456 /* in case we are about to generate a keytab during the join
457 * make sure the default upn we create is usable with kinit -k.
458 * gd */
460 if (USE_KERBEROS_KEYTAB) {
461 realm = talloc_strdup_upper(mem_ctx,
462 r->out.dns_domain_name);
465 if (!realm) {
466 return ADS_ERROR(LDAP_NO_MEMORY);
469 r->in.upn = talloc_asprintf(mem_ctx,
470 "host/%s@%s",
471 r->in.machine_name,
472 realm);
473 if (!r->in.upn) {
474 return ADS_ERROR(LDAP_NO_MEMORY);
478 /* now do the mods */
480 mods = ads_init_mods(mem_ctx);
481 if (!mods) {
482 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
485 /* fields of primary importance */
487 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
488 if (!ADS_ERR_OK(status)) {
489 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
492 return ads_gen_mod(r->in.ads, r->out.dn, mods);
496 /****************************************************************
497 ****************************************************************/
499 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
500 struct libnet_JoinCtx *r)
502 ADS_STATUS status;
503 ADS_MODLIST mods;
504 char *os_sp = NULL;
506 if (!r->in.os_name || !r->in.os_version ) {
507 return ADS_SUCCESS;
510 /* Find our DN */
512 status = libnet_join_find_machine_acct(mem_ctx, r);
513 if (!ADS_ERR_OK(status)) {
514 return status;
517 /* now do the mods */
519 mods = ads_init_mods(mem_ctx);
520 if (!mods) {
521 return ADS_ERROR(LDAP_NO_MEMORY);
524 os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
525 if (!os_sp) {
526 return ADS_ERROR(LDAP_NO_MEMORY);
529 /* fields of primary importance */
531 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
532 r->in.os_name);
533 if (!ADS_ERR_OK(status)) {
534 return status;
537 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
538 r->in.os_version);
539 if (!ADS_ERR_OK(status)) {
540 return status;
543 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
544 os_sp);
545 if (!ADS_ERR_OK(status)) {
546 return status;
549 return ads_gen_mod(r->in.ads, r->out.dn, mods);
552 /****************************************************************
553 ****************************************************************/
555 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
556 struct libnet_JoinCtx *r)
558 if (!USE_SYSTEM_KEYTAB) {
559 return true;
562 if (ads_keytab_create_default(r->in.ads) != 0) {
563 return false;
566 return true;
569 /****************************************************************
570 ****************************************************************/
572 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
573 struct libnet_JoinCtx *r)
575 uint32_t domain_func;
576 ADS_STATUS status;
577 const char *salt = NULL;
578 char *std_salt = NULL;
580 status = ads_domain_func_level(r->in.ads, &domain_func);
581 if (!ADS_ERR_OK(status)) {
582 libnet_join_set_error_string(mem_ctx, r,
583 "failed to determine domain functional level: %s",
584 ads_errstr(status));
585 return false;
588 /* go ahead and setup the default salt */
590 std_salt = kerberos_standard_des_salt();
591 if (!std_salt) {
592 libnet_join_set_error_string(mem_ctx, r,
593 "failed to obtain standard DES salt");
594 return false;
597 salt = talloc_strdup(mem_ctx, std_salt);
598 if (!salt) {
599 return false;
602 SAFE_FREE(std_salt);
604 /* if it's a Windows functional domain, we have to look for the UPN */
606 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
607 char *upn;
609 upn = ads_get_upn(r->in.ads, mem_ctx,
610 r->in.machine_name);
611 if (upn) {
612 salt = talloc_strdup(mem_ctx, upn);
613 if (!salt) {
614 return false;
619 return kerberos_secrets_store_des_salt(salt);
622 /****************************************************************
623 ****************************************************************/
625 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
626 struct libnet_JoinCtx *r)
628 ADS_STATUS status;
630 if (!r->in.ads) {
631 status = libnet_join_connect_ads(mem_ctx, r);
632 if (!ADS_ERR_OK(status)) {
633 return status;
637 status = libnet_join_set_machine_spn(mem_ctx, r);
638 if (!ADS_ERR_OK(status)) {
639 libnet_join_set_error_string(mem_ctx, r,
640 "Failed to set machine spn: %s\n"
641 "Do you have sufficient permissions to create machine "
642 "accounts?",
643 ads_errstr(status));
644 return status;
647 status = libnet_join_set_os_attributes(mem_ctx, r);
648 if (!ADS_ERR_OK(status)) {
649 libnet_join_set_error_string(mem_ctx, r,
650 "failed to set machine os attributes: %s",
651 ads_errstr(status));
652 return status;
655 status = libnet_join_set_machine_upn(mem_ctx, r);
656 if (!ADS_ERR_OK(status)) {
657 libnet_join_set_error_string(mem_ctx, r,
658 "failed to set machine upn: %s",
659 ads_errstr(status));
660 return status;
663 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
664 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
667 if (!libnet_join_create_keytab(mem_ctx, r)) {
668 libnet_join_set_error_string(mem_ctx, r,
669 "failed to create kerberos keytab");
670 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
673 return ADS_SUCCESS;
675 #endif /* HAVE_ADS */
677 /****************************************************************
678 Store the machine password and domain SID
679 ****************************************************************/
681 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
682 struct libnet_JoinCtx *r)
684 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
685 r->out.domain_sid))
687 DEBUG(1,("Failed to save domain sid\n"));
688 return false;
691 if (!secrets_store_machine_password(r->in.machine_password,
692 r->out.netbios_domain_name,
693 r->in.secure_channel_type))
695 DEBUG(1,("Failed to save machine password\n"));
696 return false;
699 return true;
702 /****************************************************************
703 Connect dc's IPC$ share
704 ****************************************************************/
706 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
707 const char *user,
708 const char *domain,
709 const char *pass,
710 bool use_kerberos,
711 struct cli_state **cli)
713 int flags = 0;
715 if (use_kerberos) {
716 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
719 if (use_kerberos && pass) {
720 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
723 return cli_full_connection(cli, NULL,
725 NULL, 0,
726 "IPC$", "IPC",
727 user,
728 domain,
729 pass,
730 flags,
731 SMB_SIGNING_DEFAULT);
734 /****************************************************************
735 Lookup domain dc's info
736 ****************************************************************/
738 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
739 struct libnet_JoinCtx *r,
740 struct cli_state **cli)
742 struct rpc_pipe_client *pipe_hnd = NULL;
743 struct policy_handle lsa_pol;
744 NTSTATUS status, result;
745 union lsa_PolicyInformation *info = NULL;
746 struct dcerpc_binding_handle *b;
748 status = libnet_join_connect_dc_ipc(r->in.dc_name,
749 r->in.admin_account,
750 r->in.admin_domain,
751 r->in.admin_password,
752 r->in.use_kerberos,
753 cli);
754 if (!NT_STATUS_IS_OK(status)) {
755 goto done;
758 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
759 &pipe_hnd);
760 if (!NT_STATUS_IS_OK(status)) {
761 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
762 nt_errstr(status)));
763 goto done;
766 b = pipe_hnd->binding_handle;
768 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
769 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
770 if (!NT_STATUS_IS_OK(status)) {
771 goto done;
774 status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
775 &lsa_pol,
776 LSA_POLICY_INFO_DNS,
777 &info,
778 &result);
779 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
780 r->out.domain_is_ad = true;
781 r->out.netbios_domain_name = info->dns.name.string;
782 r->out.dns_domain_name = info->dns.dns_domain.string;
783 r->out.forest_name = info->dns.dns_forest.string;
784 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
785 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
788 if (!NT_STATUS_IS_OK(status)) {
789 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
790 &lsa_pol,
791 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
792 &info,
793 &result);
794 if (!NT_STATUS_IS_OK(status)) {
795 goto done;
797 if (!NT_STATUS_IS_OK(result)) {
798 status = result;
799 goto done;
802 r->out.netbios_domain_name = info->account_domain.name.string;
803 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
804 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
807 dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
808 TALLOC_FREE(pipe_hnd);
810 done:
811 return status;
814 /****************************************************************
815 Do the domain join unsecure
816 ****************************************************************/
818 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
819 struct libnet_JoinCtx *r,
820 struct cli_state *cli)
822 TALLOC_CTX *frame = talloc_stackframe();
823 struct rpc_pipe_client *netlogon_pipe = NULL;
824 struct netlogon_creds_cli_context *netlogon_creds = NULL;
825 struct samr_Password current_nt_hash;
826 const char *account_name = NULL;
827 NTSTATUS status;
829 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
830 &netlogon_pipe);
831 if (!NT_STATUS_IS_OK(status)) {
832 TALLOC_FREE(frame);
833 return status;
836 if (!r->in.machine_password) {
837 r->in.machine_password = generate_random_password(mem_ctx,
838 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
839 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
840 if (r->in.machine_password == NULL) {
841 TALLOC_FREE(frame);
842 return NT_STATUS_NO_MEMORY;
846 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
847 E_md4hash(r->in.admin_password, current_nt_hash.hash);
849 account_name = talloc_asprintf(frame, "%s$",
850 r->in.machine_name);
851 if (account_name == NULL) {
852 TALLOC_FREE(frame);
853 return NT_STATUS_NO_MEMORY;
856 status = rpccli_create_netlogon_creds(netlogon_pipe->desthost,
857 r->in.domain_name,
858 account_name,
859 r->in.secure_channel_type,
860 r->in.msg_ctx,
861 frame,
862 &netlogon_creds);
863 if (!NT_STATUS_IS_OK(status)) {
864 TALLOC_FREE(frame);
865 return status;
868 status = rpccli_setup_netlogon_creds(cli,
869 netlogon_creds,
870 true, /* force_reauth */
871 current_nt_hash,
872 NULL); /* previous_nt_hash */
873 if (!NT_STATUS_IS_OK(status)) {
874 TALLOC_FREE(frame);
875 return status;
878 status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
879 netlogon_pipe->binding_handle,
880 r->in.machine_password,
881 NULL); /* new_version */
882 if (!NT_STATUS_IS_OK(status)) {
883 TALLOC_FREE(frame);
884 return status;
887 TALLOC_FREE(frame);
888 return NT_STATUS_OK;
891 /****************************************************************
892 Do the domain join
893 ****************************************************************/
895 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
896 struct libnet_JoinCtx *r,
897 struct cli_state *cli)
899 struct rpc_pipe_client *pipe_hnd = NULL;
900 struct policy_handle sam_pol, domain_pol, user_pol;
901 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
902 char *acct_name;
903 struct lsa_String lsa_acct_name;
904 uint32_t user_rid;
905 uint32_t acct_flags = ACB_WSTRUST;
906 struct samr_Ids user_rids;
907 struct samr_Ids name_types;
908 union samr_UserInfo user_info;
909 struct dcerpc_binding_handle *b = NULL;
910 unsigned int old_timeout = 0;
912 DATA_BLOB session_key = data_blob_null;
913 struct samr_CryptPassword crypt_pwd;
914 struct samr_CryptPasswordEx crypt_pwd_ex;
916 ZERO_STRUCT(sam_pol);
917 ZERO_STRUCT(domain_pol);
918 ZERO_STRUCT(user_pol);
920 switch (r->in.secure_channel_type) {
921 case SEC_CHAN_WKSTA:
922 acct_flags = ACB_WSTRUST;
923 break;
924 case SEC_CHAN_BDC:
925 acct_flags = ACB_SVRTRUST;
926 break;
927 default:
928 return NT_STATUS_INVALID_PARAMETER;
931 if (!r->in.machine_password) {
932 r->in.machine_password = generate_random_password(mem_ctx,
933 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
934 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
935 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
938 /* Open the domain */
940 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
941 &pipe_hnd);
942 if (!NT_STATUS_IS_OK(status)) {
943 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
944 nt_errstr(status)));
945 goto done;
948 b = pipe_hnd->binding_handle;
950 status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
951 if (!NT_STATUS_IS_OK(status)) {
952 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
953 nt_errstr(status)));
954 goto done;
957 status = dcerpc_samr_Connect2(b, mem_ctx,
958 pipe_hnd->desthost,
959 SAMR_ACCESS_ENUM_DOMAINS
960 | SAMR_ACCESS_LOOKUP_DOMAIN,
961 &sam_pol,
962 &result);
963 if (!NT_STATUS_IS_OK(status)) {
964 goto done;
966 if (!NT_STATUS_IS_OK(result)) {
967 status = result;
968 goto done;
971 status = dcerpc_samr_OpenDomain(b, mem_ctx,
972 &sam_pol,
973 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
974 | SAMR_DOMAIN_ACCESS_CREATE_USER
975 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
976 r->out.domain_sid,
977 &domain_pol,
978 &result);
979 if (!NT_STATUS_IS_OK(status)) {
980 goto done;
982 if (!NT_STATUS_IS_OK(result)) {
983 status = result;
984 goto done;
987 /* Create domain user */
989 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
990 if (!strlower_m(acct_name)) {
991 status = NT_STATUS_INVALID_PARAMETER;
992 goto done;
995 init_lsa_String(&lsa_acct_name, acct_name);
997 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
998 uint32_t access_desired =
999 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1000 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1001 SAMR_USER_ACCESS_SET_PASSWORD |
1002 SAMR_USER_ACCESS_GET_ATTRIBUTES |
1003 SAMR_USER_ACCESS_SET_ATTRIBUTES;
1004 uint32_t access_granted = 0;
1006 DEBUG(10,("Creating account with desired access mask: %d\n",
1007 access_desired));
1009 status = dcerpc_samr_CreateUser2(b, mem_ctx,
1010 &domain_pol,
1011 &lsa_acct_name,
1012 acct_flags,
1013 access_desired,
1014 &user_pol,
1015 &access_granted,
1016 &user_rid,
1017 &result);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 goto done;
1022 status = result;
1023 if (!NT_STATUS_IS_OK(status) &&
1024 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1026 DEBUG(10,("Creation of workstation account failed: %s\n",
1027 nt_errstr(status)));
1029 /* If NT_STATUS_ACCESS_DENIED then we have a valid
1030 username/password combo but the user does not have
1031 administrator access. */
1033 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1034 libnet_join_set_error_string(mem_ctx, r,
1035 "User specified does not have "
1036 "administrator privileges");
1039 goto done;
1042 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1043 if (!(r->in.join_flags &
1044 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1045 goto done;
1049 /* We *must* do this.... don't ask... */
1051 if (NT_STATUS_IS_OK(status)) {
1052 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1056 status = dcerpc_samr_LookupNames(b, mem_ctx,
1057 &domain_pol,
1059 &lsa_acct_name,
1060 &user_rids,
1061 &name_types,
1062 &result);
1063 if (!NT_STATUS_IS_OK(status)) {
1064 goto done;
1066 if (!NT_STATUS_IS_OK(result)) {
1067 status = result;
1068 goto done;
1070 if (user_rids.count != 1) {
1071 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1072 goto done;
1074 if (name_types.count != 1) {
1075 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1076 goto done;
1079 if (name_types.ids[0] != SID_NAME_USER) {
1080 DEBUG(0,("%s is not a user account (type=%d)\n",
1081 acct_name, name_types.ids[0]));
1082 status = NT_STATUS_INVALID_WORKSTATION;
1083 goto done;
1086 user_rid = user_rids.ids[0];
1088 /* Open handle on user */
1090 status = dcerpc_samr_OpenUser(b, mem_ctx,
1091 &domain_pol,
1092 SEC_FLAG_MAXIMUM_ALLOWED,
1093 user_rid,
1094 &user_pol,
1095 &result);
1096 if (!NT_STATUS_IS_OK(status)) {
1097 goto done;
1099 if (!NT_STATUS_IS_OK(result)) {
1100 status = result;
1101 goto done;
1104 /* Fill in the additional account flags now */
1106 acct_flags |= ACB_PWNOEXP;
1108 /* Set account flags on machine account */
1109 ZERO_STRUCT(user_info.info16);
1110 user_info.info16.acct_flags = acct_flags;
1112 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1113 &user_pol,
1115 &user_info,
1116 &result);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 dcerpc_samr_DeleteUser(b, mem_ctx,
1119 &user_pol,
1120 &result);
1122 libnet_join_set_error_string(mem_ctx, r,
1123 "Failed to set account flags for machine account (%s)\n",
1124 nt_errstr(status));
1125 goto done;
1128 if (!NT_STATUS_IS_OK(result)) {
1129 status = result;
1131 dcerpc_samr_DeleteUser(b, mem_ctx,
1132 &user_pol,
1133 &result);
1135 libnet_join_set_error_string(mem_ctx, r,
1136 "Failed to set account flags for machine account (%s)\n",
1137 nt_errstr(status));
1138 goto done;
1141 /* Set password on machine account - first try level 26 */
1144 * increase the timeout as password filter modules on the DC
1145 * might delay the operation for a significant amount of time
1147 old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1149 init_samr_CryptPasswordEx(r->in.machine_password,
1150 &session_key,
1151 &crypt_pwd_ex);
1153 user_info.info26.password = crypt_pwd_ex;
1154 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1156 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1157 &user_pol,
1159 &user_info,
1160 &result);
1162 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1164 /* retry with level 24 */
1166 init_samr_CryptPassword(r->in.machine_password,
1167 &session_key,
1168 &crypt_pwd);
1170 user_info.info24.password = crypt_pwd;
1171 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1173 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1174 &user_pol,
1176 &user_info,
1177 &result);
1180 old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1182 if (!NT_STATUS_IS_OK(status)) {
1184 dcerpc_samr_DeleteUser(b, mem_ctx,
1185 &user_pol,
1186 &result);
1188 libnet_join_set_error_string(mem_ctx, r,
1189 "Failed to set password for machine account (%s)\n",
1190 nt_errstr(status));
1191 goto done;
1193 if (!NT_STATUS_IS_OK(result)) {
1194 status = result;
1196 dcerpc_samr_DeleteUser(b, mem_ctx,
1197 &user_pol,
1198 &result);
1200 libnet_join_set_error_string(mem_ctx, r,
1201 "Failed to set password for machine account (%s)\n",
1202 nt_errstr(status));
1203 goto done;
1206 status = NT_STATUS_OK;
1208 done:
1209 if (!pipe_hnd) {
1210 return status;
1213 data_blob_clear_free(&session_key);
1215 if (is_valid_policy_hnd(&sam_pol)) {
1216 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1218 if (is_valid_policy_hnd(&domain_pol)) {
1219 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1221 if (is_valid_policy_hnd(&user_pol)) {
1222 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1224 TALLOC_FREE(pipe_hnd);
1226 return status;
1229 /****************************************************************
1230 ****************************************************************/
1232 NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1233 const char *netbios_domain_name,
1234 const char *dc_name,
1235 const bool use_kerberos)
1237 TALLOC_CTX *frame = talloc_stackframe();
1238 struct cli_state *cli = NULL;
1239 struct rpc_pipe_client *netlogon_pipe = NULL;
1240 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1241 struct netlogon_creds_CredentialState *creds = NULL;
1242 uint32_t netlogon_flags = 0;
1243 enum netr_SchannelType sec_chan_type = 0;
1244 NTSTATUS status;
1245 char *machine_password = NULL;
1246 const char *machine_name = NULL;
1247 const char *machine_account = NULL;
1248 int flags = 0;
1249 struct samr_Password current_nt_hash;
1250 struct samr_Password *previous_nt_hash = NULL;
1251 bool ok;
1253 if (!dc_name) {
1254 TALLOC_FREE(frame);
1255 return NT_STATUS_INVALID_PARAMETER;
1258 if (!secrets_init()) {
1259 TALLOC_FREE(frame);
1260 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1263 ok = get_trust_pw_clear(netbios_domain_name,
1264 &machine_password,
1265 &machine_name,
1266 &sec_chan_type);
1267 if (!ok) {
1268 TALLOC_FREE(frame);
1269 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1272 machine_account = talloc_asprintf(frame, "%s$", machine_name);
1273 if (machine_account == NULL) {
1274 SAFE_FREE(machine_password);
1275 SAFE_FREE(previous_nt_hash);
1276 TALLOC_FREE(frame);
1277 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1280 if (use_kerberos) {
1281 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1284 status = cli_full_connection(&cli, NULL,
1285 dc_name,
1286 NULL, 0,
1287 "IPC$", "IPC",
1288 machine_account,
1289 netbios_domain_name,
1290 machine_password,
1291 flags,
1292 SMB_SIGNING_DEFAULT);
1294 E_md4hash(machine_password, current_nt_hash.hash);
1295 SAFE_FREE(machine_password);
1297 if (!NT_STATUS_IS_OK(status)) {
1298 status = cli_full_connection(&cli, NULL,
1299 dc_name,
1300 NULL, 0,
1301 "IPC$", "IPC",
1303 NULL,
1306 SMB_SIGNING_DEFAULT);
1309 if (!NT_STATUS_IS_OK(status)) {
1310 SAFE_FREE(previous_nt_hash);
1311 TALLOC_FREE(frame);
1312 return status;
1315 status = rpccli_create_netlogon_creds(dc_name,
1316 netbios_domain_name,
1317 machine_account,
1318 sec_chan_type,
1319 msg_ctx,
1320 frame,
1321 &netlogon_creds);
1322 if (!NT_STATUS_IS_OK(status)) {
1323 SAFE_FREE(previous_nt_hash);
1324 cli_shutdown(cli);
1325 TALLOC_FREE(frame);
1326 return status;
1329 status = rpccli_setup_netlogon_creds(cli,
1330 netlogon_creds,
1331 true, /* force_reauth */
1332 current_nt_hash,
1333 previous_nt_hash);
1334 SAFE_FREE(previous_nt_hash);
1335 if (!NT_STATUS_IS_OK(status)) {
1336 DEBUG(0,("connect_to_domain_password_server: "
1337 "unable to open the domain client session to "
1338 "machine %s. Flags[0x%08X] Error was : %s.\n",
1339 dc_name, (unsigned)netlogon_flags,
1340 nt_errstr(status)));
1341 cli_shutdown(cli);
1342 TALLOC_FREE(frame);
1343 return status;
1346 status = netlogon_creds_cli_get(netlogon_creds,
1347 talloc_tos(),
1348 &creds);
1349 if (!NT_STATUS_IS_OK(status)) {
1350 cli_shutdown(cli);
1351 TALLOC_FREE(frame);
1352 return status;
1354 netlogon_flags = creds->negotiate_flags;
1355 TALLOC_FREE(creds);
1357 if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1358 cli_shutdown(cli);
1359 TALLOC_FREE(frame);
1360 return NT_STATUS_OK;
1363 status = cli_rpc_pipe_open_schannel_with_key(
1364 cli, &ndr_table_netlogon, NCACN_NP,
1365 netbios_domain_name,
1366 netlogon_creds, &netlogon_pipe);
1368 TALLOC_FREE(netlogon_pipe);
1370 if (!NT_STATUS_IS_OK(status)) {
1371 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1372 "on netlogon pipe to server %s for domain %s. "
1373 "Error was %s\n",
1374 smbXcli_conn_remote_name(cli->conn),
1375 netbios_domain_name, nt_errstr(status)));
1376 cli_shutdown(cli);
1377 TALLOC_FREE(frame);
1378 return status;
1381 cli_shutdown(cli);
1382 TALLOC_FREE(frame);
1383 return NT_STATUS_OK;
1386 /****************************************************************
1387 ****************************************************************/
1389 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1390 struct libnet_JoinCtx *r)
1392 NTSTATUS status;
1394 status = libnet_join_ok(r->in.msg_ctx,
1395 r->out.netbios_domain_name,
1396 r->in.dc_name,
1397 r->in.use_kerberos);
1398 if (!NT_STATUS_IS_OK(status)) {
1399 libnet_join_set_error_string(mem_ctx, r,
1400 "failed to verify domain membership after joining: %s",
1401 get_friendly_nt_error_msg(status));
1402 return WERR_SETUP_NOT_JOINED;
1405 return WERR_OK;
1408 /****************************************************************
1409 ****************************************************************/
1411 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1412 struct libnet_UnjoinCtx *r)
1414 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1415 return false;
1418 if (!secrets_delete_domain_sid(lp_workgroup())) {
1419 return false;
1422 return true;
1425 /****************************************************************
1426 ****************************************************************/
1428 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1429 struct libnet_UnjoinCtx *r)
1431 struct cli_state *cli = NULL;
1432 struct rpc_pipe_client *pipe_hnd = NULL;
1433 struct policy_handle sam_pol, domain_pol, user_pol;
1434 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1435 char *acct_name;
1436 uint32_t user_rid;
1437 struct lsa_String lsa_acct_name;
1438 struct samr_Ids user_rids;
1439 struct samr_Ids name_types;
1440 union samr_UserInfo *info = NULL;
1441 struct dcerpc_binding_handle *b = NULL;
1443 ZERO_STRUCT(sam_pol);
1444 ZERO_STRUCT(domain_pol);
1445 ZERO_STRUCT(user_pol);
1447 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1448 r->in.admin_account,
1449 r->in.admin_domain,
1450 r->in.admin_password,
1451 r->in.use_kerberos,
1452 &cli);
1453 if (!NT_STATUS_IS_OK(status)) {
1454 goto done;
1457 /* Open the domain */
1459 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1460 &pipe_hnd);
1461 if (!NT_STATUS_IS_OK(status)) {
1462 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1463 nt_errstr(status)));
1464 goto done;
1467 b = pipe_hnd->binding_handle;
1469 status = dcerpc_samr_Connect2(b, mem_ctx,
1470 pipe_hnd->desthost,
1471 SEC_FLAG_MAXIMUM_ALLOWED,
1472 &sam_pol,
1473 &result);
1474 if (!NT_STATUS_IS_OK(status)) {
1475 goto done;
1477 if (!NT_STATUS_IS_OK(result)) {
1478 status = result;
1479 goto done;
1482 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1483 &sam_pol,
1484 SEC_FLAG_MAXIMUM_ALLOWED,
1485 r->in.domain_sid,
1486 &domain_pol,
1487 &result);
1488 if (!NT_STATUS_IS_OK(status)) {
1489 goto done;
1491 if (!NT_STATUS_IS_OK(result)) {
1492 status = result;
1493 goto done;
1496 /* Create domain user */
1498 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1499 if (!strlower_m(acct_name)) {
1500 status = NT_STATUS_INVALID_PARAMETER;
1501 goto done;
1504 init_lsa_String(&lsa_acct_name, acct_name);
1506 status = dcerpc_samr_LookupNames(b, mem_ctx,
1507 &domain_pol,
1509 &lsa_acct_name,
1510 &user_rids,
1511 &name_types,
1512 &result);
1514 if (!NT_STATUS_IS_OK(status)) {
1515 goto done;
1517 if (!NT_STATUS_IS_OK(result)) {
1518 status = result;
1519 goto done;
1521 if (user_rids.count != 1) {
1522 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1523 goto done;
1525 if (name_types.count != 1) {
1526 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1527 goto done;
1530 if (name_types.ids[0] != SID_NAME_USER) {
1531 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1532 name_types.ids[0]));
1533 status = NT_STATUS_INVALID_WORKSTATION;
1534 goto done;
1537 user_rid = user_rids.ids[0];
1539 /* Open handle on user */
1541 status = dcerpc_samr_OpenUser(b, mem_ctx,
1542 &domain_pol,
1543 SEC_FLAG_MAXIMUM_ALLOWED,
1544 user_rid,
1545 &user_pol,
1546 &result);
1547 if (!NT_STATUS_IS_OK(status)) {
1548 goto done;
1550 if (!NT_STATUS_IS_OK(result)) {
1551 status = result;
1552 goto done;
1555 /* Get user info */
1557 status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1558 &user_pol,
1560 &info,
1561 &result);
1562 if (!NT_STATUS_IS_OK(status)) {
1563 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1564 goto done;
1566 if (!NT_STATUS_IS_OK(result)) {
1567 status = result;
1568 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1569 goto done;
1572 /* now disable and setuser info */
1574 info->info16.acct_flags |= ACB_DISABLED;
1576 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1577 &user_pol,
1579 info,
1580 &result);
1581 if (!NT_STATUS_IS_OK(status)) {
1582 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1583 goto done;
1585 if (!NT_STATUS_IS_OK(result)) {
1586 status = result;
1587 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1588 goto done;
1590 status = result;
1591 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1593 done:
1594 if (pipe_hnd && b) {
1595 if (is_valid_policy_hnd(&domain_pol)) {
1596 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1598 if (is_valid_policy_hnd(&sam_pol)) {
1599 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1601 TALLOC_FREE(pipe_hnd);
1604 if (cli) {
1605 cli_shutdown(cli);
1608 return status;
1611 /****************************************************************
1612 ****************************************************************/
1614 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1616 WERROR werr = WERR_OK;
1617 sbcErr err;
1618 struct smbconf_ctx *ctx;
1620 err = smbconf_init_reg(r, &ctx, NULL);
1621 if (!SBC_ERROR_IS_OK(err)) {
1622 werr = WERR_NO_SUCH_SERVICE;
1623 goto done;
1626 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1628 err = smbconf_set_global_parameter(ctx, "security", "user");
1629 if (!SBC_ERROR_IS_OK(err)) {
1630 werr = WERR_NO_SUCH_SERVICE;
1631 goto done;
1634 err = smbconf_set_global_parameter(ctx, "workgroup",
1635 r->in.domain_name);
1636 if (!SBC_ERROR_IS_OK(err)) {
1637 werr = WERR_NO_SUCH_SERVICE;
1638 goto done;
1641 smbconf_delete_global_parameter(ctx, "realm");
1642 goto done;
1645 err = smbconf_set_global_parameter(ctx, "security", "domain");
1646 if (!SBC_ERROR_IS_OK(err)) {
1647 werr = WERR_NO_SUCH_SERVICE;
1648 goto done;
1651 err = smbconf_set_global_parameter(ctx, "workgroup",
1652 r->out.netbios_domain_name);
1653 if (!SBC_ERROR_IS_OK(err)) {
1654 werr = WERR_NO_SUCH_SERVICE;
1655 goto done;
1658 if (r->out.domain_is_ad) {
1659 err = smbconf_set_global_parameter(ctx, "security", "ads");
1660 if (!SBC_ERROR_IS_OK(err)) {
1661 werr = WERR_NO_SUCH_SERVICE;
1662 goto done;
1665 err = smbconf_set_global_parameter(ctx, "realm",
1666 r->out.dns_domain_name);
1667 if (!SBC_ERROR_IS_OK(err)) {
1668 werr = WERR_NO_SUCH_SERVICE;
1669 goto done;
1673 done:
1674 smbconf_shutdown(ctx);
1675 return werr;
1678 /****************************************************************
1679 ****************************************************************/
1681 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1683 WERROR werr = WERR_OK;
1684 sbcErr err;
1685 struct smbconf_ctx *ctx;
1687 err = smbconf_init_reg(r, &ctx, NULL);
1688 if (!SBC_ERROR_IS_OK(err)) {
1689 werr = WERR_NO_SUCH_SERVICE;
1690 goto done;
1693 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1695 err = smbconf_set_global_parameter(ctx, "security", "user");
1696 if (!SBC_ERROR_IS_OK(err)) {
1697 werr = WERR_NO_SUCH_SERVICE;
1698 goto done;
1701 err = smbconf_delete_global_parameter(ctx, "workgroup");
1702 if (!SBC_ERROR_IS_OK(err)) {
1703 werr = WERR_NO_SUCH_SERVICE;
1704 goto done;
1707 smbconf_delete_global_parameter(ctx, "realm");
1710 done:
1711 smbconf_shutdown(ctx);
1712 return werr;
1715 /****************************************************************
1716 ****************************************************************/
1718 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1720 WERROR werr;
1722 if (!W_ERROR_IS_OK(r->out.result)) {
1723 return r->out.result;
1726 if (!r->in.modify_config) {
1727 return WERR_OK;
1730 werr = do_join_modify_vals_config(r);
1731 if (!W_ERROR_IS_OK(werr)) {
1732 return werr;
1735 lp_load_global(get_dyn_CONFIGFILE());
1737 r->out.modified_config = true;
1738 r->out.result = werr;
1740 return werr;
1743 /****************************************************************
1744 ****************************************************************/
1746 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1748 WERROR werr;
1750 if (!W_ERROR_IS_OK(r->out.result)) {
1751 return r->out.result;
1754 if (!r->in.modify_config) {
1755 return WERR_OK;
1758 werr = do_unjoin_modify_vals_config(r);
1759 if (!W_ERROR_IS_OK(werr)) {
1760 return werr;
1763 lp_load_global(get_dyn_CONFIGFILE());
1765 r->out.modified_config = true;
1766 r->out.result = werr;
1768 return werr;
1771 /****************************************************************
1772 ****************************************************************/
1774 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1775 const char *domain_str,
1776 const char **domain_p,
1777 const char **dc_p)
1779 char *domain = NULL;
1780 char *dc = NULL;
1781 const char *p = NULL;
1783 if (!domain_str || !domain_p || !dc_p) {
1784 return false;
1787 p = strchr_m(domain_str, '\\');
1789 if (p != NULL) {
1790 domain = talloc_strndup(mem_ctx, domain_str,
1791 PTR_DIFF(p, domain_str));
1792 dc = talloc_strdup(mem_ctx, p+1);
1793 if (!dc) {
1794 return false;
1796 } else {
1797 domain = talloc_strdup(mem_ctx, domain_str);
1798 dc = NULL;
1800 if (!domain) {
1801 return false;
1804 *domain_p = domain;
1806 if (!*dc_p && dc) {
1807 *dc_p = dc;
1810 return true;
1813 /****************************************************************
1814 ****************************************************************/
1816 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1817 struct libnet_JoinCtx *r)
1819 if (!r->in.domain_name) {
1820 libnet_join_set_error_string(mem_ctx, r,
1821 "No domain name defined");
1822 return WERR_INVALID_PARAM;
1825 if (strlen(r->in.machine_name) > 15) {
1826 libnet_join_set_error_string(mem_ctx, r,
1827 "Our netbios name can be at most 15 chars long, "
1828 "\"%s\" is %u chars long\n",
1829 r->in.machine_name,
1830 (unsigned int)strlen(r->in.machine_name));
1831 return WERR_INVALID_PARAM;
1834 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1835 &r->in.domain_name,
1836 &r->in.dc_name)) {
1837 libnet_join_set_error_string(mem_ctx, r,
1838 "Failed to parse domain name");
1839 return WERR_INVALID_PARAM;
1842 if (IS_DC) {
1843 return WERR_SETUP_DOMAIN_CONTROLLER;
1846 if (!r->in.admin_domain) {
1847 char *admin_domain = NULL;
1848 char *admin_account = NULL;
1849 split_domain_user(mem_ctx,
1850 r->in.admin_account,
1851 &admin_domain,
1852 &admin_account);
1853 r->in.admin_domain = admin_domain;
1854 r->in.admin_account = admin_account;
1857 if (!secrets_init()) {
1858 libnet_join_set_error_string(mem_ctx, r,
1859 "Unable to open secrets database");
1860 return WERR_CAN_NOT_COMPLETE;
1863 return WERR_OK;
1866 /****************************************************************
1867 ****************************************************************/
1869 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1871 NTSTATUS status;
1873 /* Try adding dom admins to builtin\admins. Only log failures. */
1874 status = create_builtin_administrators(domain_sid);
1875 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1876 DEBUG(10,("Unable to auto-add domain administrators to "
1877 "BUILTIN\\Administrators during join because "
1878 "winbindd must be running.\n"));
1879 } else if (!NT_STATUS_IS_OK(status)) {
1880 DEBUG(5, ("Failed to auto-add domain administrators to "
1881 "BUILTIN\\Administrators during join: %s\n",
1882 nt_errstr(status)));
1885 /* Try adding dom users to builtin\users. Only log failures. */
1886 status = create_builtin_users(domain_sid);
1887 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1888 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1889 "during join because winbindd must be running.\n"));
1890 } else if (!NT_STATUS_IS_OK(status)) {
1891 DEBUG(5, ("Failed to auto-add domain administrators to "
1892 "BUILTIN\\Administrators during join: %s\n",
1893 nt_errstr(status)));
1897 /****************************************************************
1898 ****************************************************************/
1900 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1901 struct libnet_JoinCtx *r)
1903 WERROR werr;
1905 if (!W_ERROR_IS_OK(r->out.result)) {
1906 return r->out.result;
1909 werr = do_JoinConfig(r);
1910 if (!W_ERROR_IS_OK(werr)) {
1911 return werr;
1914 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1915 return WERR_OK;
1918 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1919 if (r->out.dns_domain_name) {
1920 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1923 #ifdef HAVE_ADS
1924 if (r->out.domain_is_ad &&
1925 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1926 ADS_STATUS ads_status;
1928 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1929 if (!ADS_ERR_OK(ads_status)) {
1930 return WERR_GENERAL_FAILURE;
1933 #endif /* HAVE_ADS */
1935 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1937 return WERR_OK;
1940 /****************************************************************
1941 ****************************************************************/
1943 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1945 if (r->in.ads) {
1946 ads_destroy(&r->in.ads);
1949 return 0;
1952 /****************************************************************
1953 ****************************************************************/
1955 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1957 if (r->in.ads) {
1958 ads_destroy(&r->in.ads);
1961 return 0;
1964 /****************************************************************
1965 ****************************************************************/
1967 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1968 struct libnet_JoinCtx **r)
1970 struct libnet_JoinCtx *ctx;
1972 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1973 if (!ctx) {
1974 return WERR_NOMEM;
1977 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1979 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
1980 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1982 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1984 *r = ctx;
1986 return WERR_OK;
1989 /****************************************************************
1990 ****************************************************************/
1992 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1993 struct libnet_UnjoinCtx **r)
1995 struct libnet_UnjoinCtx *ctx;
1997 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1998 if (!ctx) {
1999 return WERR_NOMEM;
2002 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2004 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2005 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2007 *r = ctx;
2009 return WERR_OK;
2012 /****************************************************************
2013 ****************************************************************/
2015 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2016 struct libnet_JoinCtx *r)
2018 bool valid_security = false;
2019 bool valid_workgroup = false;
2020 bool valid_realm = false;
2022 /* check if configuration is already set correctly */
2024 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2026 switch (r->out.domain_is_ad) {
2027 case false:
2028 valid_security = (lp_security() == SEC_DOMAIN);
2029 if (valid_workgroup && valid_security) {
2030 /* nothing to be done */
2031 return WERR_OK;
2033 break;
2034 case true:
2035 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2036 switch (lp_security()) {
2037 case SEC_DOMAIN:
2038 case SEC_ADS:
2039 valid_security = true;
2042 if (valid_workgroup && valid_realm && valid_security) {
2043 /* nothing to be done */
2044 return WERR_OK;
2046 break;
2049 /* check if we are supposed to manipulate configuration */
2051 if (!r->in.modify_config) {
2053 char *wrong_conf = talloc_strdup(mem_ctx, "");
2055 if (!valid_workgroup) {
2056 wrong_conf = talloc_asprintf_append(wrong_conf,
2057 "\"workgroup\" set to '%s', should be '%s'",
2058 lp_workgroup(), r->out.netbios_domain_name);
2059 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2062 if (!valid_realm) {
2063 wrong_conf = talloc_asprintf_append(wrong_conf,
2064 "\"realm\" set to '%s', should be '%s'",
2065 lp_realm(), r->out.dns_domain_name);
2066 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2069 if (!valid_security) {
2070 const char *sec = NULL;
2071 switch (lp_security()) {
2072 case SEC_USER: sec = "user"; break;
2073 case SEC_DOMAIN: sec = "domain"; break;
2074 case SEC_ADS: sec = "ads"; break;
2076 wrong_conf = talloc_asprintf_append(wrong_conf,
2077 "\"security\" set to '%s', should be %s",
2078 sec, r->out.domain_is_ad ?
2079 "either 'domain' or 'ads'" : "'domain'");
2080 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2083 libnet_join_set_error_string(mem_ctx, r,
2084 "Invalid configuration (%s) and configuration modification "
2085 "was not requested", wrong_conf);
2086 return WERR_CAN_NOT_COMPLETE;
2089 /* check if we are able to manipulate configuration */
2091 if (!lp_config_backend_is_registry()) {
2092 libnet_join_set_error_string(mem_ctx, r,
2093 "Configuration manipulation requested but not "
2094 "supported by backend");
2095 return WERR_NOT_SUPPORTED;
2098 return WERR_OK;
2101 /****************************************************************
2102 ****************************************************************/
2104 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2105 struct libnet_JoinCtx *r)
2107 NTSTATUS status;
2108 WERROR werr;
2109 struct cli_state *cli = NULL;
2110 #ifdef HAVE_ADS
2111 ADS_STATUS ads_status;
2112 #endif /* HAVE_ADS */
2114 if (!r->in.dc_name) {
2115 struct netr_DsRGetDCNameInfo *info;
2116 const char *dc;
2117 status = dsgetdcname(mem_ctx,
2118 r->in.msg_ctx,
2119 r->in.domain_name,
2120 NULL,
2121 NULL,
2122 DS_FORCE_REDISCOVERY |
2123 DS_DIRECTORY_SERVICE_REQUIRED |
2124 DS_WRITABLE_REQUIRED |
2125 DS_RETURN_DNS_NAME,
2126 &info);
2127 if (!NT_STATUS_IS_OK(status)) {
2128 libnet_join_set_error_string(mem_ctx, r,
2129 "failed to find DC for domain %s",
2130 r->in.domain_name,
2131 get_friendly_nt_error_msg(status));
2132 return WERR_DCNOTFOUND;
2135 dc = strip_hostname(info->dc_unc);
2136 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2137 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2140 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2141 if (!NT_STATUS_IS_OK(status)) {
2142 libnet_join_set_error_string(mem_ctx, r,
2143 "failed to lookup DC info for domain '%s' over rpc: %s",
2144 r->in.domain_name, get_friendly_nt_error_msg(status));
2145 return ntstatus_to_werror(status);
2148 werr = libnet_join_check_config(mem_ctx, r);
2149 if (!W_ERROR_IS_OK(werr)) {
2150 goto done;
2153 #ifdef HAVE_ADS
2155 create_local_private_krb5_conf_for_domain(
2156 r->out.dns_domain_name, r->out.netbios_domain_name,
2157 NULL, smbXcli_conn_remote_sockaddr(cli->conn));
2159 if (r->out.domain_is_ad && r->in.account_ou &&
2160 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2162 ads_status = libnet_join_connect_ads(mem_ctx, r);
2163 if (!ADS_ERR_OK(ads_status)) {
2164 return WERR_DEFAULT_JOIN_REQUIRED;
2167 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2168 if (!ADS_ERR_OK(ads_status)) {
2169 libnet_join_set_error_string(mem_ctx, r,
2170 "failed to precreate account in ou %s: %s",
2171 r->in.account_ou,
2172 ads_errstr(ads_status));
2173 return WERR_DEFAULT_JOIN_REQUIRED;
2176 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2178 #endif /* HAVE_ADS */
2180 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2181 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2182 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2183 } else {
2184 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2186 if (!NT_STATUS_IS_OK(status)) {
2187 libnet_join_set_error_string(mem_ctx, r,
2188 "failed to join domain '%s' over rpc: %s",
2189 r->in.domain_name, get_friendly_nt_error_msg(status));
2190 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2191 return WERR_SETUP_ALREADY_JOINED;
2193 werr = ntstatus_to_werror(status);
2194 goto done;
2197 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2198 werr = WERR_SETUP_NOT_JOINED;
2199 goto done;
2202 werr = WERR_OK;
2204 done:
2205 if (cli) {
2206 cli_shutdown(cli);
2209 return werr;
2212 /****************************************************************
2213 ****************************************************************/
2215 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2216 struct libnet_JoinCtx *r)
2218 WERROR werr;
2219 struct libnet_UnjoinCtx *u = NULL;
2221 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2222 if (!W_ERROR_IS_OK(werr)) {
2223 return werr;
2226 u->in.debug = r->in.debug;
2227 u->in.dc_name = r->in.dc_name;
2228 u->in.domain_name = r->in.domain_name;
2229 u->in.admin_account = r->in.admin_account;
2230 u->in.admin_password = r->in.admin_password;
2231 u->in.modify_config = r->in.modify_config;
2232 u->in.use_kerberos = r->in.use_kerberos;
2233 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2234 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2236 werr = libnet_Unjoin(mem_ctx, u);
2237 TALLOC_FREE(u);
2239 return werr;
2242 /****************************************************************
2243 ****************************************************************/
2245 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2246 struct libnet_JoinCtx *r)
2248 WERROR werr;
2250 if (r->in.debug) {
2251 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2254 ZERO_STRUCT(r->out);
2256 werr = libnet_join_pre_processing(mem_ctx, r);
2257 if (!W_ERROR_IS_OK(werr)) {
2258 goto done;
2261 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2262 werr = libnet_DomainJoin(mem_ctx, r);
2263 if (!W_ERROR_IS_OK(werr)) {
2264 goto done;
2268 werr = libnet_join_post_processing(mem_ctx, r);
2269 if (!W_ERROR_IS_OK(werr)) {
2270 goto done;
2273 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2274 werr = libnet_join_post_verify(mem_ctx, r);
2275 if (!W_ERROR_IS_OK(werr)) {
2276 libnet_join_rollback(mem_ctx, r);
2280 done:
2281 r->out.result = werr;
2283 if (r->in.debug) {
2284 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2286 return werr;
2289 /****************************************************************
2290 ****************************************************************/
2292 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2293 struct libnet_UnjoinCtx *r)
2295 NTSTATUS status;
2297 if (!r->in.domain_sid) {
2298 struct dom_sid sid;
2299 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2300 libnet_unjoin_set_error_string(mem_ctx, r,
2301 "Unable to fetch domain sid: are we joined?");
2302 return WERR_SETUP_NOT_JOINED;
2304 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2305 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2308 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2309 !r->in.delete_machine_account) {
2310 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2311 return WERR_OK;
2314 if (!r->in.dc_name) {
2315 struct netr_DsRGetDCNameInfo *info;
2316 const char *dc;
2317 status = dsgetdcname(mem_ctx,
2318 r->in.msg_ctx,
2319 r->in.domain_name,
2320 NULL,
2321 NULL,
2322 DS_DIRECTORY_SERVICE_REQUIRED |
2323 DS_WRITABLE_REQUIRED |
2324 DS_RETURN_DNS_NAME,
2325 &info);
2326 if (!NT_STATUS_IS_OK(status)) {
2327 libnet_unjoin_set_error_string(mem_ctx, r,
2328 "failed to find DC for domain %s",
2329 r->in.domain_name,
2330 get_friendly_nt_error_msg(status));
2331 return WERR_DCNOTFOUND;
2334 dc = strip_hostname(info->dc_unc);
2335 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2336 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2339 #ifdef HAVE_ADS
2340 /* for net ads leave, try to delete the account. If it works,
2341 no sense in disabling. If it fails, we can still try to
2342 disable it. jmcd */
2344 if (r->in.delete_machine_account) {
2345 ADS_STATUS ads_status;
2346 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2347 if (ADS_ERR_OK(ads_status)) {
2348 /* dirty hack */
2349 r->out.dns_domain_name =
2350 talloc_strdup(mem_ctx,
2351 r->in.ads->server.realm);
2352 ads_status =
2353 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2355 if (!ADS_ERR_OK(ads_status)) {
2356 libnet_unjoin_set_error_string(mem_ctx, r,
2357 "failed to remove machine account from AD: %s",
2358 ads_errstr(ads_status));
2359 } else {
2360 r->out.deleted_machine_account = true;
2361 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2362 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2363 return WERR_OK;
2366 #endif /* HAVE_ADS */
2368 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2369 "disable". */
2370 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2371 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2372 if (!NT_STATUS_IS_OK(status)) {
2373 libnet_unjoin_set_error_string(mem_ctx, r,
2374 "failed to disable machine account via rpc: %s",
2375 get_friendly_nt_error_msg(status));
2376 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2377 return WERR_SETUP_NOT_JOINED;
2379 return ntstatus_to_werror(status);
2382 r->out.disabled_machine_account = true;
2385 /* If disable succeeded or was not requested at all, we
2386 should be getting rid of our end of things */
2388 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2390 return WERR_OK;
2393 /****************************************************************
2394 ****************************************************************/
2396 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2397 struct libnet_UnjoinCtx *r)
2399 if (!r->in.domain_name) {
2400 libnet_unjoin_set_error_string(mem_ctx, r,
2401 "No domain name defined");
2402 return WERR_INVALID_PARAM;
2405 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2406 &r->in.domain_name,
2407 &r->in.dc_name)) {
2408 libnet_unjoin_set_error_string(mem_ctx, r,
2409 "Failed to parse domain name");
2410 return WERR_INVALID_PARAM;
2413 if (IS_DC) {
2414 return WERR_SETUP_DOMAIN_CONTROLLER;
2417 if (!r->in.admin_domain) {
2418 char *admin_domain = NULL;
2419 char *admin_account = NULL;
2420 split_domain_user(mem_ctx,
2421 r->in.admin_account,
2422 &admin_domain,
2423 &admin_account);
2424 r->in.admin_domain = admin_domain;
2425 r->in.admin_account = admin_account;
2428 if (!secrets_init()) {
2429 libnet_unjoin_set_error_string(mem_ctx, r,
2430 "Unable to open secrets database");
2431 return WERR_CAN_NOT_COMPLETE;
2434 return WERR_OK;
2437 /****************************************************************
2438 ****************************************************************/
2440 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2441 struct libnet_UnjoinCtx *r)
2443 saf_delete(r->out.netbios_domain_name);
2444 saf_delete(r->out.dns_domain_name);
2446 return libnet_unjoin_config(r);
2449 /****************************************************************
2450 ****************************************************************/
2452 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2453 struct libnet_UnjoinCtx *r)
2455 WERROR werr;
2457 if (r->in.debug) {
2458 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2461 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2462 if (!W_ERROR_IS_OK(werr)) {
2463 goto done;
2466 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2467 werr = libnet_DomainUnjoin(mem_ctx, r);
2468 if (!W_ERROR_IS_OK(werr)) {
2469 libnet_unjoin_config(r);
2470 goto done;
2474 werr = libnet_unjoin_post_processing(mem_ctx, r);
2475 if (!W_ERROR_IS_OK(werr)) {
2476 goto done;
2479 done:
2480 r->out.result = werr;
2482 if (r->in.debug) {
2483 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2486 return werr;