1/*
2 *  Unix SMB/CIFS implementation.
3 *  libnet Join Support
4 *  Copyright (C) Gerald (Jerry) Carter 2006
5 *  Copyright (C) Guenther Deschner 2007-2008
6 *
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.
11 *
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.
16 *
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/>.
19 */
20
21#include "includes.h"
22#include "libnet/libnet.h"
23#include "libcli/auth/libcli_auth.h"
24#include "../librpc/gen_ndr/cli_samr.h"
25#include "../librpc/gen_ndr/cli_lsa.h"
26
27/****************************************************************
28****************************************************************/
29
30#define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
31	do { \
32		char *str = NULL; \
33		str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
34		DEBUG(1,("libnet_Join:\n%s", str)); \
35		TALLOC_FREE(str); \
36	} while (0)
37
38#define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
39	LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
40#define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
41	LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
42
43#define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
44	do { \
45		char *str = NULL; \
46		str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
47		DEBUG(1,("libnet_Unjoin:\n%s", str)); \
48		TALLOC_FREE(str); \
49	} while (0)
50
51#define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
52	LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
53#define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
54	LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
55
56/****************************************************************
57****************************************************************/
58
59static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
60					 struct libnet_JoinCtx *r,
61					 const char *format, ...)
62{
63	va_list args;
64
65	if (r->out.error_string) {
66		return;
67	}
68
69	va_start(args, format);
70	r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
71	va_end(args);
72}
73
74/****************************************************************
75****************************************************************/
76
77static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
78					   struct libnet_UnjoinCtx *r,
79					   const char *format, ...)
80{
81	va_list args;
82
83	if (r->out.error_string) {
84		return;
85	}
86
87	va_start(args, format);
88	r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
89	va_end(args);
90}
91
92#ifdef WITH_ADS
93
94/****************************************************************
95****************************************************************/
96
97static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
98				     const char *netbios_domain_name,
99				     const char *dc_name,
100				     const char *user_name,
101				     const char *password,
102				     ADS_STRUCT **ads)
103{
104	ADS_STATUS status;
105	ADS_STRUCT *my_ads = NULL;
106
107	my_ads = ads_init(dns_domain_name,
108			  netbios_domain_name,
109			  dc_name);
110	if (!my_ads) {
111		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
112	}
113
114	if (user_name) {
115		SAFE_FREE(my_ads->auth.user_name);
116		my_ads->auth.user_name = SMB_STRDUP(user_name);
117	}
118
119	if (password) {
120		SAFE_FREE(my_ads->auth.password);
121		my_ads->auth.password = SMB_STRDUP(password);
122	}
123
124	status = ads_connect_user_creds(my_ads);
125	if (!ADS_ERR_OK(status)) {
126		ads_destroy(&my_ads);
127		return status;
128	}
129
130	*ads = my_ads;
131	return ADS_SUCCESS;
132}
133
134/****************************************************************
135****************************************************************/
136
137static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
138					  struct libnet_JoinCtx *r)
139{
140	ADS_STATUS status;
141
142	status = libnet_connect_ads(r->out.dns_domain_name,
143				    r->out.netbios_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_join_set_error_string(mem_ctx, r,
150			"failed to connect to AD: %s",
151			ads_errstr(status));
152		return status;
153	}
154
155	if (!r->out.netbios_domain_name) {
156		r->out.netbios_domain_name = talloc_strdup(mem_ctx,
157							   r->in.ads->server.workgroup);
158		ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
159	}
160
161	if (!r->out.dns_domain_name) {
162		r->out.dns_domain_name = talloc_strdup(mem_ctx,
163						       r->in.ads->config.realm);
164		ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
165	}
166
167	r->out.domain_is_ad = true;
168
169	return ADS_SUCCESS;
170}
171
172/****************************************************************
173****************************************************************/
174
175static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
176					    struct libnet_UnjoinCtx *r)
177{
178	ADS_STATUS status;
179
180	status = libnet_connect_ads(r->in.domain_name,
181				    r->in.domain_name,
182				    r->in.dc_name,
183				    r->in.admin_account,
184				    r->in.admin_password,
185				    &r->in.ads);
186	if (!ADS_ERR_OK(status)) {
187		libnet_unjoin_set_error_string(mem_ctx, r,
188			"failed to connect to AD: %s",
189			ads_errstr(status));
190	}
191
192	return status;
193}
194
195/****************************************************************
196 join a domain using ADS (LDAP mods)
197****************************************************************/
198
199static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
200						     struct libnet_JoinCtx *r)
201{
202	ADS_STATUS status;
203	LDAPMessage *res = NULL;
204	const char *attrs[] = { "dn", NULL };
205	bool moved = false;
206
207	status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
208	if (!ADS_ERR_OK(status)) {
209		return status;
210	}
211
212	status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
213	if (!ADS_ERR_OK(status)) {
214		return status;
215	}
216
217	if (ads_count_replies(r->in.ads, res) != 1) {
218		ads_msgfree(r->in.ads, res);
219		return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
220	}
221
222	ads_msgfree(r->in.ads, res);
223
224	/* Attempt to create the machine account and bail if this fails.
225	   Assume that the admin wants exactly what they requested */
226
227	status = ads_create_machine_acct(r->in.ads,
228					 r->in.machine_name,
229					 r->in.account_ou);
230
231	if (ADS_ERR_OK(status)) {
232		DEBUG(1,("machine account creation created\n"));
233		return status;
234	} else  if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
235		    (status.err.rc == LDAP_ALREADY_EXISTS)) {
236		status = ADS_SUCCESS;
237	}
238
239	if (!ADS_ERR_OK(status)) {
240		DEBUG(1,("machine account creation failed\n"));
241		return status;
242	}
243
244	status = ads_move_machine_acct(r->in.ads,
245				       r->in.machine_name,
246				       r->in.account_ou,
247				       &moved);
248	if (!ADS_ERR_OK(status)) {
249		DEBUG(1,("failure to locate/move pre-existing "
250			"machine account\n"));
251		return status;
252	}
253
254	DEBUG(1,("The machine account %s the specified OU.\n",
255		moved ? "was moved into" : "already exists in"));
256
257	return status;
258}
259
260/****************************************************************
261****************************************************************/
262
263static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
264						    struct libnet_UnjoinCtx *r)
265{
266	ADS_STATUS status;
267
268	if (!r->in.ads) {
269		status = libnet_unjoin_connect_ads(mem_ctx, r);
270		if (!ADS_ERR_OK(status)) {
271			libnet_unjoin_set_error_string(mem_ctx, r,
272				"failed to connect to AD: %s",
273				ads_errstr(status));
274			return status;
275		}
276	}
277
278	status = ads_leave_realm(r->in.ads, r->in.machine_name);
279	if (!ADS_ERR_OK(status)) {
280		libnet_unjoin_set_error_string(mem_ctx, r,
281			"failed to leave realm: %s",
282			ads_errstr(status));
283		return status;
284	}
285
286	return ADS_SUCCESS;
287}
288
289/****************************************************************
290****************************************************************/
291
292static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
293						struct libnet_JoinCtx *r)
294{
295	ADS_STATUS status;
296	LDAPMessage *res = NULL;
297	char *dn = NULL;
298
299	if (!r->in.machine_name) {
300		return ADS_ERROR(LDAP_NO_MEMORY);
301	}
302
303	status = ads_find_machine_acct(r->in.ads,
304				       &res,
305				       r->in.machine_name);
306	if (!ADS_ERR_OK(status)) {
307		return status;
308	}
309
310	if (ads_count_replies(r->in.ads, res) != 1) {
311		status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
312		goto done;
313	}
314
315	dn = ads_get_dn(r->in.ads, mem_ctx, res);
316	if (!dn) {
317		status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
318		goto done;
319	}
320
321	r->out.dn = talloc_strdup(mem_ctx, dn);
322	if (!r->out.dn) {
323		status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
324		goto done;
325	}
326
327 done:
328	ads_msgfree(r->in.ads, res);
329	TALLOC_FREE(dn);
330
331	return status;
332}
333
334/****************************************************************
335 Set a machines dNSHostName and servicePrincipalName attributes
336****************************************************************/
337
338static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
339					      struct libnet_JoinCtx *r)
340{
341	ADS_STATUS status;
342	ADS_MODLIST mods;
343	fstring my_fqdn;
344	const char *spn_array[3] = {NULL, NULL, NULL};
345	char *spn = NULL;
346
347	/* Find our DN */
348
349	status = libnet_join_find_machine_acct(mem_ctx, r);
350	if (!ADS_ERR_OK(status)) {
351		return status;
352	}
353
354	/* Windows only creates HOST/shortname & HOST/fqdn. */
355
356	spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
357	if (!spn) {
358		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
359	}
360	strupper_m(spn);
361	spn_array[0] = spn;
362
363	if (!name_to_fqdn(my_fqdn, r->in.machine_name)
364	    || (strchr(my_fqdn, '.') == NULL)) {
365		fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
366			     r->out.dns_domain_name);
367	}
368
369	strlower_m(my_fqdn);
370
371	if (!strequal(my_fqdn, r->in.machine_name)) {
372		spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
373		if (!spn) {
374			return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
375		}
376		spn_array[1] = spn;
377	}
378
379	mods = ads_init_mods(mem_ctx);
380	if (!mods) {
381		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
382	}
383
384	/* fields of primary importance */
385
386	status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
387	if (!ADS_ERR_OK(status)) {
388		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
389	}
390
391	status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
392				 spn_array);
393	if (!ADS_ERR_OK(status)) {
394		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
395	}
396
397	return ads_gen_mod(r->in.ads, r->out.dn, mods);
398}
399
400/****************************************************************
401****************************************************************/
402
403static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
404					      struct libnet_JoinCtx *r)
405{
406	ADS_STATUS status;
407	ADS_MODLIST mods;
408
409	if (!r->in.create_upn) {
410		return ADS_SUCCESS;
411	}
412
413	/* Find our DN */
414
415	status = libnet_join_find_machine_acct(mem_ctx, r);
416	if (!ADS_ERR_OK(status)) {
417		return status;
418	}
419
420	if (!r->in.upn) {
421		r->in.upn = talloc_asprintf(mem_ctx,
422					    "host/%s@%s",
423					    r->in.machine_name,
424					    r->out.dns_domain_name);
425		if (!r->in.upn) {
426			return ADS_ERROR(LDAP_NO_MEMORY);
427		}
428	}
429
430	/* now do the mods */
431
432	mods = ads_init_mods(mem_ctx);
433	if (!mods) {
434		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
435	}
436
437	/* fields of primary importance */
438
439	status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
440	if (!ADS_ERR_OK(status)) {
441		return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
442	}
443
444	return ads_gen_mod(r->in.ads, r->out.dn, mods);
445}
446
447
448/****************************************************************
449****************************************************************/
450
451static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
452						struct libnet_JoinCtx *r)
453{
454	ADS_STATUS status;
455	ADS_MODLIST mods;
456	char *os_sp = NULL;
457
458	if (!r->in.os_name || !r->in.os_version ) {
459		return ADS_SUCCESS;
460	}
461
462	/* Find our DN */
463
464	status = libnet_join_find_machine_acct(mem_ctx, r);
465	if (!ADS_ERR_OK(status)) {
466		return status;
467	}
468
469	/* now do the mods */
470
471	mods = ads_init_mods(mem_ctx);
472	if (!mods) {
473		return ADS_ERROR(LDAP_NO_MEMORY);
474	}
475
476	os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
477	if (!os_sp) {
478		return ADS_ERROR(LDAP_NO_MEMORY);
479	}
480
481	/* fields of primary importance */
482
483	status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
484			     r->in.os_name);
485	if (!ADS_ERR_OK(status)) {
486		return status;
487	}
488
489	status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
490			     r->in.os_version);
491	if (!ADS_ERR_OK(status)) {
492		return status;
493	}
494
495	status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
496			     os_sp);
497	if (!ADS_ERR_OK(status)) {
498		return status;
499	}
500
501	return ads_gen_mod(r->in.ads, r->out.dn, mods);
502}
503
504/****************************************************************
505****************************************************************/
506
507static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
508				      struct libnet_JoinCtx *r)
509{
510	if (!USE_SYSTEM_KEYTAB) {
511		return true;
512	}
513
514	if (ads_keytab_create_default(r->in.ads) != 0) {
515		return false;
516	}
517
518	return true;
519}
520
521/****************************************************************
522****************************************************************/
523
524static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
525						 struct libnet_JoinCtx *r)
526{
527	uint32_t domain_func;
528	ADS_STATUS status;
529	const char *salt = NULL;
530	char *std_salt = NULL;
531
532	status = ads_domain_func_level(r->in.ads, &domain_func);
533	if (!ADS_ERR_OK(status)) {
534		libnet_join_set_error_string(mem_ctx, r,
535			"failed to determine domain functional level: %s",
536			ads_errstr(status));
537		return false;
538	}
539
540	/* go ahead and setup the default salt */
541
542	std_salt = kerberos_standard_des_salt();
543	if (!std_salt) {
544		libnet_join_set_error_string(mem_ctx, r,
545			"failed to obtain standard DES salt");
546		return false;
547	}
548
549	salt = talloc_strdup(mem_ctx, std_salt);
550	if (!salt) {
551		return false;
552	}
553
554	SAFE_FREE(std_salt);
555
556	/* if it's a Windows functional domain, we have to look for the UPN */
557
558	if (domain_func == DS_DOMAIN_FUNCTION_2000) {
559		char *upn;
560
561		upn = ads_get_upn(r->in.ads, mem_ctx,
562				  r->in.machine_name);
563		if (upn) {
564			salt = talloc_strdup(mem_ctx, upn);
565			if (!salt) {
566				return false;
567			}
568		}
569	}
570
571	return kerberos_secrets_store_des_salt(salt);
572}
573
574/****************************************************************
575****************************************************************/
576
577static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
578						  struct libnet_JoinCtx *r)
579{
580	ADS_STATUS status;
581
582	if (!r->in.ads) {
583		status = libnet_join_connect_ads(mem_ctx, r);
584		if (!ADS_ERR_OK(status)) {
585			return status;
586		}
587	}
588
589	status = libnet_join_set_machine_spn(mem_ctx, r);
590	if (!ADS_ERR_OK(status)) {
591		libnet_join_set_error_string(mem_ctx, r,
592			"failed to set machine spn: %s",
593			ads_errstr(status));
594		return status;
595	}
596
597	status = libnet_join_set_os_attributes(mem_ctx, r);
598	if (!ADS_ERR_OK(status)) {
599		libnet_join_set_error_string(mem_ctx, r,
600			"failed to set machine os attributes: %s",
601			ads_errstr(status));
602		return status;
603	}
604
605	status = libnet_join_set_machine_upn(mem_ctx, r);
606	if (!ADS_ERR_OK(status)) {
607		libnet_join_set_error_string(mem_ctx, r,
608			"failed to set machine upn: %s",
609			ads_errstr(status));
610		return status;
611	}
612
613	if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
614		return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
615	}
616
617	if (!libnet_join_create_keytab(mem_ctx, r)) {
618		libnet_join_set_error_string(mem_ctx, r,
619			"failed to create kerberos keytab");
620		return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
621	}
622
623	return ADS_SUCCESS;
624}
625#endif /* WITH_ADS */
626
627/****************************************************************
628 Store the machine password and domain SID
629****************************************************************/
630
631static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
632						 struct libnet_JoinCtx *r)
633{
634	if (!secrets_store_domain_sid(r->out.netbios_domain_name,
635				      r->out.domain_sid))
636	{
637		DEBUG(1,("Failed to save domain sid\n"));
638		return false;
639	}
640
641	if (!secrets_store_machine_password(r->in.machine_password,
642					    r->out.netbios_domain_name,
643					    r->in.secure_channel_type))
644	{
645		DEBUG(1,("Failed to save machine password\n"));
646		return false;
647	}
648
649	return true;
650}
651
652/****************************************************************
653 Connect dc's IPC$ share
654****************************************************************/
655
656static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
657					   const char *user,
658					   const char *pass,
659					   bool use_kerberos,
660					   struct cli_state **cli)
661{
662	int flags = 0;
663
664	if (use_kerberos) {
665		flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
666	}
667
668	if (use_kerberos && pass) {
669		flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
670	}
671
672	return cli_full_connection(cli, NULL,
673				   dc,
674				   NULL, 0,
675				   "IPC$", "IPC",
676				   user,
677				   NULL,
678				   pass,
679				   flags,
680				   Undefined, NULL);
681}
682
683/****************************************************************
684 Lookup domain dc's info
685****************************************************************/
686
687static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
688					  struct libnet_JoinCtx *r,
689					  struct cli_state **cli)
690{
691	struct rpc_pipe_client *pipe_hnd = NULL;
692	struct policy_handle lsa_pol;
693	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
694	union lsa_PolicyInformation *info = NULL;
695
696	status = libnet_join_connect_dc_ipc(r->in.dc_name,
697					    r->in.admin_account,
698					    r->in.admin_password,
699					    r->in.use_kerberos,
700					    cli);
701	if (!NT_STATUS_IS_OK(status)) {
702		goto done;
703	}
704
705	status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
706					  &pipe_hnd);
707	if (!NT_STATUS_IS_OK(status)) {
708		DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
709			nt_errstr(status)));
710		goto done;
711	}
712
713	status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
714					SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
715	if (!NT_STATUS_IS_OK(status)) {
716		goto done;
717	}
718
719	status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx,
720					     &lsa_pol,
721					     LSA_POLICY_INFO_DNS,
722					     &info);
723	if (NT_STATUS_IS_OK(status)) {
724		r->out.domain_is_ad = true;
725		r->out.netbios_domain_name = info->dns.name.string;
726		r->out.dns_domain_name = info->dns.dns_domain.string;
727		r->out.forest_name = info->dns.dns_forest.string;
728		r->out.domain_sid = sid_dup_talloc(mem_ctx, info->dns.sid);
729		NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
730	}
731
732	if (!NT_STATUS_IS_OK(status)) {
733		status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
734						    &lsa_pol,
735						    LSA_POLICY_INFO_ACCOUNT_DOMAIN,
736						    &info);
737		if (!NT_STATUS_IS_OK(status)) {
738			goto done;
739		}
740
741		r->out.netbios_domain_name = info->account_domain.name.string;
742		r->out.domain_sid = sid_dup_talloc(mem_ctx, info->account_domain.sid);
743		NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
744	}
745
746	rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
747	TALLOC_FREE(pipe_hnd);
748
749 done:
750	return status;
751}
752
753/****************************************************************
754 Do the domain join unsecure
755****************************************************************/
756
757static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
758						    struct libnet_JoinCtx *r,
759						    struct cli_state *cli)
760{
761	struct rpc_pipe_client *pipe_hnd = NULL;
762	unsigned char orig_trust_passwd_hash[16];
763	unsigned char new_trust_passwd_hash[16];
764	fstring trust_passwd;
765	NTSTATUS status;
766
767	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
768					  &pipe_hnd);
769	if (!NT_STATUS_IS_OK(status)) {
770		return status;
771	}
772
773	if (!r->in.machine_password) {
774		r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
775		NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
776	}
777
778	E_md4hash(r->in.machine_password, new_trust_passwd_hash);
779
780	/* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
781	fstrcpy(trust_passwd, r->in.admin_password);
782	strlower_m(trust_passwd);
783
784	/*
785	 * Machine names can be 15 characters, but the max length on
786	 * a password is 14.  --jerry
787	 */
788
789	trust_passwd[14] = '\0';
790
791	E_md4hash(trust_passwd, orig_trust_passwd_hash);
792
793	status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx,
794						    r->in.machine_name,
795						    orig_trust_passwd_hash,
796						    r->in.machine_password,
797						    new_trust_passwd_hash,
798						    r->in.secure_channel_type);
799
800	return status;
801}
802
803/****************************************************************
804 Do the domain join
805****************************************************************/
806
807static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
808					   struct libnet_JoinCtx *r,
809					   struct cli_state *cli)
810{
811	struct rpc_pipe_client *pipe_hnd = NULL;
812	struct policy_handle sam_pol, domain_pol, user_pol;
813	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
814	char *acct_name;
815	struct lsa_String lsa_acct_name;
816	uint32_t user_rid;
817	uint32_t acct_flags = ACB_WSTRUST;
818	struct samr_Ids user_rids;
819	struct samr_Ids name_types;
820	union samr_UserInfo user_info;
821
822	struct samr_CryptPassword crypt_pwd;
823	struct samr_CryptPasswordEx crypt_pwd_ex;
824
825	ZERO_STRUCT(sam_pol);
826	ZERO_STRUCT(domain_pol);
827	ZERO_STRUCT(user_pol);
828
829	switch (r->in.secure_channel_type) {
830	case SEC_CHAN_WKSTA:
831		acct_flags = ACB_WSTRUST;
832		break;
833	case SEC_CHAN_BDC:
834		acct_flags = ACB_SVRTRUST;
835		break;
836	default:
837		return NT_STATUS_INVALID_PARAMETER;
838	}
839
840	if (!r->in.machine_password) {
841		r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
842		NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
843	}
844
845	/* Open the domain */
846
847	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
848					  &pipe_hnd);
849	if (!NT_STATUS_IS_OK(status)) {
850		DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
851			nt_errstr(status)));
852		goto done;
853	}
854
855	status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
856				      pipe_hnd->desthost,
857				      SAMR_ACCESS_ENUM_DOMAINS
858				      | SAMR_ACCESS_LOOKUP_DOMAIN,
859				      &sam_pol);
860	if (!NT_STATUS_IS_OK(status)) {
861		goto done;
862	}
863
864	status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
865					&sam_pol,
866					SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
867					| SAMR_DOMAIN_ACCESS_CREATE_USER
868					| SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
869					r->out.domain_sid,
870					&domain_pol);
871	if (!NT_STATUS_IS_OK(status)) {
872		goto done;
873	}
874
875	/* Create domain user */
876
877	acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
878	strlower_m(acct_name);
879
880	init_lsa_String(&lsa_acct_name, acct_name);
881
882	if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
883		uint32_t access_desired =
884			SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
885			SEC_STD_WRITE_DAC | SEC_STD_DELETE |
886			SAMR_USER_ACCESS_SET_PASSWORD |
887			SAMR_USER_ACCESS_GET_ATTRIBUTES |
888			SAMR_USER_ACCESS_SET_ATTRIBUTES;
889		uint32_t access_granted = 0;
890
891		DEBUG(10,("Creating account with desired access mask: %d\n",
892			access_desired));
893
894		status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
895						 &domain_pol,
896						 &lsa_acct_name,
897						 acct_flags,
898						 access_desired,
899						 &user_pol,
900						 &access_granted,
901						 &user_rid);
902		if (!NT_STATUS_IS_OK(status) &&
903		    !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
904
905			DEBUG(10,("Creation of workstation account failed: %s\n",
906				nt_errstr(status)));
907
908			/* If NT_STATUS_ACCESS_DENIED then we have a valid
909			   username/password combo but the user does not have
910			   administrator access. */
911
912			if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
913				libnet_join_set_error_string(mem_ctx, r,
914					"User specified does not have "
915					"administrator privileges");
916			}
917
918			goto done;
919		}
920
921		if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
922			if (!(r->in.join_flags &
923			      WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
924				goto done;
925			}
926		}
927
928		/* We *must* do this.... don't ask... */
929
930		if (NT_STATUS_IS_OK(status)) {
931			rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
932		}
933	}
934
935	status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
936					 &domain_pol,
937					 1,
938					 &lsa_acct_name,
939					 &user_rids,
940					 &name_types);
941	if (!NT_STATUS_IS_OK(status)) {
942		goto done;
943	}
944
945	if (name_types.ids[0] != SID_NAME_USER) {
946		DEBUG(0,("%s is not a user account (type=%d)\n",
947			acct_name, name_types.ids[0]));
948		status = NT_STATUS_INVALID_WORKSTATION;
949		goto done;
950	}
951
952	user_rid = user_rids.ids[0];
953
954	/* Open handle on user */
955
956	status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
957				      &domain_pol,
958				      SEC_FLAG_MAXIMUM_ALLOWED,
959				      user_rid,
960				      &user_pol);
961	if (!NT_STATUS_IS_OK(status)) {
962		goto done;
963	}
964
965	/* Fill in the additional account flags now */
966
967	acct_flags |= ACB_PWNOEXP;
968	if (r->out.domain_is_ad) {
969#if !defined(ENCTYPE_ARCFOUR_HMAC)
970		acct_flags |= ACB_USE_DES_KEY_ONLY;
971#endif
972		;;
973	}
974
975	/* Set account flags on machine account */
976	ZERO_STRUCT(user_info.info16);
977	user_info.info16.acct_flags = acct_flags;
978
979	status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
980					 &user_pol,
981					 16,
982					 &user_info);
983
984	if (!NT_STATUS_IS_OK(status)) {
985
986		rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
987				       &user_pol);
988
989		libnet_join_set_error_string(mem_ctx, r,
990			"Failed to set account flags for machine account (%s)\n",
991			nt_errstr(status));
992		goto done;
993	}
994
995	/* Set password on machine account - first try level 26 */
996
997	init_samr_CryptPasswordEx(r->in.machine_password,
998				  &cli->user_session_key,
999				  &crypt_pwd_ex);
1000
1001	user_info.info26.password = crypt_pwd_ex;
1002	user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1003
1004	status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1005					  &user_pol,
1006					  26,
1007					  &user_info);
1008
1009	if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
1010
1011		/* retry with level 24 */
1012
1013		init_samr_CryptPassword(r->in.machine_password,
1014					&cli->user_session_key,
1015					&crypt_pwd);
1016
1017		user_info.info24.password = crypt_pwd;
1018		user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1019
1020		status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1021						  &user_pol,
1022						  24,
1023						  &user_info);
1024	}
1025
1026	if (!NT_STATUS_IS_OK(status)) {
1027
1028		rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
1029				       &user_pol);
1030
1031		libnet_join_set_error_string(mem_ctx, r,
1032			"Failed to set password for machine account (%s)\n",
1033			nt_errstr(status));
1034		goto done;
1035	}
1036
1037	status = NT_STATUS_OK;
1038
1039 done:
1040	if (!pipe_hnd) {
1041		return status;
1042	}
1043
1044	if (is_valid_policy_hnd(&sam_pol)) {
1045		rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1046	}
1047	if (is_valid_policy_hnd(&domain_pol)) {
1048		rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1049	}
1050	if (is_valid_policy_hnd(&user_pol)) {
1051		rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1052	}
1053	TALLOC_FREE(pipe_hnd);
1054
1055	return status;
1056}
1057
1058/****************************************************************
1059****************************************************************/
1060
1061NTSTATUS libnet_join_ok(const char *netbios_domain_name,
1062			const char *machine_name,
1063			const char *dc_name)
1064{
1065	uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
1066	struct cli_state *cli = NULL;
1067	struct rpc_pipe_client *pipe_hnd = NULL;
1068	struct rpc_pipe_client *netlogon_pipe = NULL;
1069	NTSTATUS status;
1070	char *machine_password = NULL;
1071	char *machine_account = NULL;
1072
1073	if (!dc_name) {
1074		return NT_STATUS_INVALID_PARAMETER;
1075	}
1076
1077	if (!secrets_init()) {
1078		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1079	}
1080
1081	machine_password = secrets_fetch_machine_password(netbios_domain_name,
1082							  NULL, NULL);
1083	if (!machine_password) {
1084		return NT_STATUS_NO_TRUST_LSA_SECRET;
1085	}
1086
1087	if (asprintf(&machine_account, "%s$", machine_name) == -1) {
1088		SAFE_FREE(machine_password);
1089		return NT_STATUS_NO_MEMORY;
1090	}
1091
1092	status = cli_full_connection(&cli, NULL,
1093				     dc_name,
1094				     NULL, 0,
1095				     "IPC$", "IPC",
1096				     machine_account,
1097				     NULL,
1098				     machine_password,
1099				     0,
1100				     Undefined, NULL);
1101	free(machine_account);
1102	free(machine_password);
1103
1104	if (!NT_STATUS_IS_OK(status)) {
1105		status = cli_full_connection(&cli, NULL,
1106					     dc_name,
1107					     NULL, 0,
1108					     "IPC$", "IPC",
1109					     "",
1110					     NULL,
1111					     "",
1112					     0,
1113					     Undefined, NULL);
1114	}
1115
1116	if (!NT_STATUS_IS_OK(status)) {
1117		return status;
1118	}
1119
1120	status = get_schannel_session_key(cli, netbios_domain_name,
1121					  &neg_flags, &netlogon_pipe);
1122	if (!NT_STATUS_IS_OK(status)) {
1123		if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
1124			cli_shutdown(cli);
1125			return NT_STATUS_OK;
1126		}
1127
1128		DEBUG(0,("libnet_join_ok: failed to get schannel session "
1129			"key from server %s for domain %s. Error was %s\n",
1130		cli->desthost, netbios_domain_name, nt_errstr(status)));
1131		cli_shutdown(cli);
1132		return status;
1133	}
1134
1135	if (!lp_client_schannel()) {
1136		cli_shutdown(cli);
1137		return NT_STATUS_OK;
1138	}
1139
1140	status = cli_rpc_pipe_open_schannel_with_key(
1141		cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
1142		DCERPC_AUTH_LEVEL_PRIVACY,
1143		netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd);
1144
1145	cli_shutdown(cli);
1146
1147	if (!NT_STATUS_IS_OK(status)) {
1148		DEBUG(0,("libnet_join_ok: failed to open schannel session "
1149			"on netlogon pipe to server %s for domain %s. "
1150			"Error was %s\n",
1151			cli->desthost, netbios_domain_name, nt_errstr(status)));
1152		return status;
1153	}
1154
1155	return NT_STATUS_OK;
1156}
1157
1158/****************************************************************
1159****************************************************************/
1160
1161static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1162				      struct libnet_JoinCtx *r)
1163{
1164	NTSTATUS status;
1165
1166	status = libnet_join_ok(r->out.netbios_domain_name,
1167				r->in.machine_name,
1168				r->in.dc_name);
1169	if (!NT_STATUS_IS_OK(status)) {
1170		libnet_join_set_error_string(mem_ctx, r,
1171			"failed to verify domain membership after joining: %s",
1172			get_friendly_nt_error_msg(status));
1173		return WERR_SETUP_NOT_JOINED;
1174	}
1175
1176	return WERR_OK;
1177}
1178
1179/****************************************************************
1180****************************************************************/
1181
1182static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1183						    struct libnet_UnjoinCtx *r)
1184{
1185	if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1186		return false;
1187	}
1188
1189	if (!secrets_delete_domain_sid(lp_workgroup())) {
1190		return false;
1191	}
1192
1193	return true;
1194}
1195
1196/****************************************************************
1197****************************************************************/
1198
1199static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1200					     struct libnet_UnjoinCtx *r)
1201{
1202	struct cli_state *cli = NULL;
1203	struct rpc_pipe_client *pipe_hnd = NULL;
1204	struct policy_handle sam_pol, domain_pol, user_pol;
1205	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1206	char *acct_name;
1207	uint32_t user_rid;
1208	struct lsa_String lsa_acct_name;
1209	struct samr_Ids user_rids;
1210	struct samr_Ids name_types;
1211	union samr_UserInfo *info = NULL;
1212
1213	ZERO_STRUCT(sam_pol);
1214	ZERO_STRUCT(domain_pol);
1215	ZERO_STRUCT(user_pol);
1216
1217	status = libnet_join_connect_dc_ipc(r->in.dc_name,
1218					    r->in.admin_account,
1219					    r->in.admin_password,
1220					    r->in.use_kerberos,
1221					    &cli);
1222	if (!NT_STATUS_IS_OK(status)) {
1223		goto done;
1224	}
1225
1226	/* Open the domain */
1227
1228	status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
1229					  &pipe_hnd);
1230	if (!NT_STATUS_IS_OK(status)) {
1231		DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1232			nt_errstr(status)));
1233		goto done;
1234	}
1235
1236	status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1237				      pipe_hnd->desthost,
1238				      SEC_FLAG_MAXIMUM_ALLOWED,
1239				      &sam_pol);
1240	if (!NT_STATUS_IS_OK(status)) {
1241		goto done;
1242	}
1243
1244	status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1245					&sam_pol,
1246					SEC_FLAG_MAXIMUM_ALLOWED,
1247					r->in.domain_sid,
1248					&domain_pol);
1249	if (!NT_STATUS_IS_OK(status)) {
1250		goto done;
1251	}
1252
1253	/* Create domain user */
1254
1255	acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1256	strlower_m(acct_name);
1257
1258	init_lsa_String(&lsa_acct_name, acct_name);
1259
1260	status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1261					 &domain_pol,
1262					 1,
1263					 &lsa_acct_name,
1264					 &user_rids,
1265					 &name_types);
1266
1267	if (!NT_STATUS_IS_OK(status)) {
1268		goto done;
1269	}
1270
1271	if (name_types.ids[0] != SID_NAME_USER) {
1272		DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1273			name_types.ids[0]));
1274		status = NT_STATUS_INVALID_WORKSTATION;
1275		goto done;
1276	}
1277
1278	user_rid = user_rids.ids[0];
1279
1280	/* Open handle on user */
1281
1282	status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1283				      &domain_pol,
1284				      SEC_FLAG_MAXIMUM_ALLOWED,
1285				      user_rid,
1286				      &user_pol);
1287	if (!NT_STATUS_IS_OK(status)) {
1288		goto done;
1289	}
1290
1291	/* Get user info */
1292
1293	status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1294					   &user_pol,
1295					   16,
1296					   &info);
1297	if (!NT_STATUS_IS_OK(status)) {
1298		rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1299		goto done;
1300	}
1301
1302	/* now disable and setuser info */
1303
1304	info->info16.acct_flags |= ACB_DISABLED;
1305
1306	status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1307					 &user_pol,
1308					 16,
1309					 info);
1310
1311	rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1312
1313done:
1314	if (pipe_hnd) {
1315		if (is_valid_policy_hnd(&domain_pol)) {
1316			rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1317		}
1318		if (is_valid_policy_hnd(&sam_pol)) {
1319			rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1320		}
1321		TALLOC_FREE(pipe_hnd);
1322	}
1323
1324	if (cli) {
1325		cli_shutdown(cli);
1326	}
1327
1328	return status;
1329}
1330
1331/****************************************************************
1332****************************************************************/
1333
1334static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1335{
1336	WERROR werr;
1337	struct smbconf_ctx *ctx;
1338
1339	werr = smbconf_init_reg(r, &ctx, NULL);
1340	if (!W_ERROR_IS_OK(werr)) {
1341		goto done;
1342	}
1343
1344	if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1345
1346		werr = smbconf_set_global_parameter(ctx, "security", "user");
1347		W_ERROR_NOT_OK_GOTO_DONE(werr);
1348
1349		werr = smbconf_set_global_parameter(ctx, "workgroup",
1350						    r->in.domain_name);
1351
1352		smbconf_delete_global_parameter(ctx, "realm");
1353		goto done;
1354	}
1355
1356	werr = smbconf_set_global_parameter(ctx, "security", "domain");
1357	W_ERROR_NOT_OK_GOTO_DONE(werr);
1358
1359	werr = smbconf_set_global_parameter(ctx, "workgroup",
1360					    r->out.netbios_domain_name);
1361	W_ERROR_NOT_OK_GOTO_DONE(werr);
1362
1363	if (r->out.domain_is_ad) {
1364		werr = smbconf_set_global_parameter(ctx, "security", "ads");
1365		W_ERROR_NOT_OK_GOTO_DONE(werr);
1366
1367		werr = smbconf_set_global_parameter(ctx, "realm",
1368						    r->out.dns_domain_name);
1369		W_ERROR_NOT_OK_GOTO_DONE(werr);
1370	}
1371
1372 done:
1373	smbconf_shutdown(ctx);
1374	return werr;
1375}
1376
1377/****************************************************************
1378****************************************************************/
1379
1380static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1381{
1382	WERROR werr = WERR_OK;
1383	struct smbconf_ctx *ctx;
1384
1385	werr = smbconf_init_reg(r, &ctx, NULL);
1386	if (!W_ERROR_IS_OK(werr)) {
1387		goto done;
1388	}
1389
1390	if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1391
1392		werr = smbconf_set_global_parameter(ctx, "security", "user");
1393		W_ERROR_NOT_OK_GOTO_DONE(werr);
1394
1395		werr = smbconf_delete_global_parameter(ctx, "workgroup");
1396		W_ERROR_NOT_OK_GOTO_DONE(werr);
1397
1398		smbconf_delete_global_parameter(ctx, "realm");
1399	}
1400
1401 done:
1402	smbconf_shutdown(ctx);
1403	return werr;
1404}
1405
1406/****************************************************************
1407****************************************************************/
1408
1409static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1410{
1411	WERROR werr;
1412
1413	if (!W_ERROR_IS_OK(r->out.result)) {
1414		return r->out.result;
1415	}
1416
1417	if (!r->in.modify_config) {
1418		return WERR_OK;
1419	}
1420
1421	werr = do_join_modify_vals_config(r);
1422	if (!W_ERROR_IS_OK(werr)) {
1423		return werr;
1424	}
1425
1426	lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1427
1428	r->out.modified_config = true;
1429	r->out.result = werr;
1430
1431	return werr;
1432}
1433
1434/****************************************************************
1435****************************************************************/
1436
1437static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1438{
1439	WERROR werr;
1440
1441	if (!W_ERROR_IS_OK(r->out.result)) {
1442		return r->out.result;
1443	}
1444
1445	if (!r->in.modify_config) {
1446		return WERR_OK;
1447	}
1448
1449	werr = do_unjoin_modify_vals_config(r);
1450	if (!W_ERROR_IS_OK(werr)) {
1451		return werr;
1452	}
1453
1454	lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1455
1456	r->out.modified_config = true;
1457	r->out.result = werr;
1458
1459	return werr;
1460}
1461
1462/****************************************************************
1463****************************************************************/
1464
1465static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1466				   const char *domain_str,
1467				   const char **domain_p,
1468				   const char **dc_p)
1469{
1470	char *domain = NULL;
1471	char *dc = NULL;
1472	const char *p = NULL;
1473
1474	if (!domain_str || !domain_p || !dc_p) {
1475		return false;
1476	}
1477
1478	p = strchr_m(domain_str, '\\');
1479
1480	if (p != NULL) {
1481		domain = talloc_strndup(mem_ctx, domain_str,
1482					 PTR_DIFF(p, domain_str));
1483		dc = talloc_strdup(mem_ctx, p+1);
1484		if (!dc) {
1485			return false;
1486		}
1487	} else {
1488		domain = talloc_strdup(mem_ctx, domain_str);
1489		dc = NULL;
1490	}
1491	if (!domain) {
1492		return false;
1493	}
1494
1495	*domain_p = domain;
1496
1497	if (!*dc_p && dc) {
1498		*dc_p = dc;
1499	}
1500
1501	return true;
1502}
1503
1504/****************************************************************
1505****************************************************************/
1506
1507static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1508					 struct libnet_JoinCtx *r)
1509{
1510	if (!r->in.domain_name) {
1511		libnet_join_set_error_string(mem_ctx, r,
1512			"No domain name defined");
1513		return WERR_INVALID_PARAM;
1514	}
1515
1516	if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1517				    &r->in.domain_name,
1518				    &r->in.dc_name)) {
1519		libnet_join_set_error_string(mem_ctx, r,
1520			"Failed to parse domain name");
1521		return WERR_INVALID_PARAM;
1522	}
1523
1524	if (IS_DC) {
1525		return WERR_SETUP_DOMAIN_CONTROLLER;
1526	}
1527
1528	if (!secrets_init()) {
1529		libnet_join_set_error_string(mem_ctx, r,
1530			"Unable to open secrets database");
1531		return WERR_CAN_NOT_COMPLETE;
1532	}
1533
1534	return WERR_OK;
1535}
1536
1537/****************************************************************
1538****************************************************************/
1539
1540static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1541{
1542	NTSTATUS status;
1543
1544	/* Try adding dom admins to builtin\admins. Only log failures. */
1545	status = create_builtin_administrators(domain_sid);
1546	if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1547		DEBUG(10,("Unable to auto-add domain administrators to "
1548			  "BUILTIN\\Administrators during join because "
1549			  "winbindd must be running."));
1550	} else if (!NT_STATUS_IS_OK(status)) {
1551		DEBUG(5, ("Failed to auto-add domain administrators to "
1552			  "BUILTIN\\Administrators during join: %s\n",
1553			  nt_errstr(status)));
1554	}
1555
1556	/* Try adding dom users to builtin\users. Only log failures. */
1557	status = create_builtin_users(domain_sid);
1558	if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1559		DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1560			  "during join because winbindd must be running."));
1561	} else if (!NT_STATUS_IS_OK(status)) {
1562		DEBUG(5, ("Failed to auto-add domain administrators to "
1563			  "BUILTIN\\Administrators during join: %s\n",
1564			  nt_errstr(status)));
1565	}
1566}
1567
1568/****************************************************************
1569****************************************************************/
1570
1571static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1572					  struct libnet_JoinCtx *r)
1573{
1574	WERROR werr;
1575
1576	if (!W_ERROR_IS_OK(r->out.result)) {
1577		return r->out.result;
1578	}
1579
1580	werr = do_JoinConfig(r);
1581	if (!W_ERROR_IS_OK(werr)) {
1582		return werr;
1583	}
1584
1585	if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1586		return WERR_OK;
1587	}
1588
1589	saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1590	if (r->out.dns_domain_name) {
1591		saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1592	}
1593
1594#ifdef WITH_ADS
1595	if (r->out.domain_is_ad &&
1596	    !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1597		ADS_STATUS ads_status;
1598
1599		ads_status  = libnet_join_post_processing_ads(mem_ctx, r);
1600		if (!ADS_ERR_OK(ads_status)) {
1601			return WERR_GENERAL_FAILURE;
1602		}
1603	}
1604#endif /* WITH_ADS */
1605
1606	libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1607
1608	return WERR_OK;
1609}
1610
1611/****************************************************************
1612****************************************************************/
1613
1614static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1615{
1616	const char *krb5_cc_env = NULL;
1617
1618	if (r->in.ads) {
1619		ads_destroy(&r->in.ads);
1620	}
1621
1622	krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1623	if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1624		unsetenv(KRB5_ENV_CCNAME);
1625	}
1626
1627	return 0;
1628}
1629
1630/****************************************************************
1631****************************************************************/
1632
1633static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1634{
1635	const char *krb5_cc_env = NULL;
1636
1637	if (r->in.ads) {
1638		ads_destroy(&r->in.ads);
1639	}
1640
1641	krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1642	if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1643		unsetenv(KRB5_ENV_CCNAME);
1644	}
1645
1646	return 0;
1647}
1648
1649/****************************************************************
1650****************************************************************/
1651
1652WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1653			   struct libnet_JoinCtx **r)
1654{
1655	struct libnet_JoinCtx *ctx;
1656	const char *krb5_cc_env = NULL;
1657
1658	ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1659	if (!ctx) {
1660		return WERR_NOMEM;
1661	}
1662
1663	talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1664
1665	ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1666	W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1667
1668	krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1669	if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1670		krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1671		W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1672		setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1673	}
1674
1675	ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1676
1677	*r = ctx;
1678
1679	return WERR_OK;
1680}
1681
1682/****************************************************************
1683****************************************************************/
1684
1685WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1686			     struct libnet_UnjoinCtx **r)
1687{
1688	struct libnet_UnjoinCtx *ctx;
1689	const char *krb5_cc_env = NULL;
1690
1691	ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1692	if (!ctx) {
1693		return WERR_NOMEM;
1694	}
1695
1696	talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1697
1698	ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1699	W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1700
1701	krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1702	if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1703		krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1704		W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1705		setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1706	}
1707
1708	*r = ctx;
1709
1710	return WERR_OK;
1711}
1712
1713/****************************************************************
1714****************************************************************/
1715
1716static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
1717				       struct libnet_JoinCtx *r)
1718{
1719	bool valid_security = false;
1720	bool valid_workgroup = false;
1721	bool valid_realm = false;
1722
1723	/* check if configuration is already set correctly */
1724
1725	valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
1726
1727	switch (r->out.domain_is_ad) {
1728		case false:
1729			valid_security = (lp_security() == SEC_DOMAIN);
1730			if (valid_workgroup && valid_security) {
1731				/* nothing to be done */
1732				return WERR_OK;
1733			}
1734			break;
1735		case true:
1736			valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
1737			switch (lp_security()) {
1738			case SEC_DOMAIN:
1739			case SEC_ADS:
1740				valid_security = true;
1741			}
1742
1743			if (valid_workgroup && valid_realm && valid_security) {
1744				/* nothing to be done */
1745				return WERR_OK;
1746			}
1747			break;
1748	}
1749
1750	/* check if we are supposed to manipulate configuration */
1751
1752	if (!r->in.modify_config) {
1753
1754		char *wrong_conf = talloc_strdup(mem_ctx, "");
1755
1756		if (!valid_workgroup) {
1757			wrong_conf = talloc_asprintf_append(wrong_conf,
1758				"\"workgroup\" set to '%s', should be '%s'",
1759				lp_workgroup(), r->out.netbios_domain_name);
1760			W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1761		}
1762
1763		if (!valid_realm) {
1764			wrong_conf = talloc_asprintf_append(wrong_conf,
1765				"\"realm\" set to '%s', should be '%s'",
1766				lp_realm(), r->out.dns_domain_name);
1767			W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1768		}
1769
1770		if (!valid_security) {
1771			const char *sec = NULL;
1772			switch (lp_security()) {
1773			case SEC_SHARE: sec = "share"; break;
1774			case SEC_USER:  sec = "user"; break;
1775			case SEC_DOMAIN: sec = "domain"; break;
1776			case SEC_ADS: sec = "ads"; break;
1777			}
1778			wrong_conf = talloc_asprintf_append(wrong_conf,
1779				"\"security\" set to '%s', should be %s",
1780				sec, r->out.domain_is_ad ?
1781				"either 'domain' or 'ads'" : "'domain'");
1782			W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1783		}
1784
1785		libnet_join_set_error_string(mem_ctx, r,
1786			"Invalid configuration (%s) and configuration modification "
1787			"was not requested", wrong_conf);
1788		return WERR_CAN_NOT_COMPLETE;
1789	}
1790
1791	/* check if we are able to manipulate configuration */
1792
1793	if (!lp_config_backend_is_registry()) {
1794		libnet_join_set_error_string(mem_ctx, r,
1795			"Configuration manipulation requested but not "
1796			"supported by backend");
1797		return WERR_NOT_SUPPORTED;
1798	}
1799
1800	return WERR_OK;
1801}
1802
1803/****************************************************************
1804****************************************************************/
1805
1806static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1807				struct libnet_JoinCtx *r)
1808{
1809	NTSTATUS status;
1810	WERROR werr;
1811	struct cli_state *cli = NULL;
1812#ifdef WITH_ADS
1813	ADS_STATUS ads_status;
1814#endif /* WITH_ADS */
1815
1816	if (!r->in.dc_name) {
1817		struct netr_DsRGetDCNameInfo *info;
1818		const char *dc;
1819		status = dsgetdcname(mem_ctx,
1820				     r->in.msg_ctx,
1821				     r->in.domain_name,
1822				     NULL,
1823				     NULL,
1824				     DS_FORCE_REDISCOVERY |
1825				     DS_DIRECTORY_SERVICE_REQUIRED |
1826				     DS_WRITABLE_REQUIRED |
1827				     DS_RETURN_DNS_NAME,
1828				     &info);
1829		if (!NT_STATUS_IS_OK(status)) {
1830			libnet_join_set_error_string(mem_ctx, r,
1831				"failed to find DC for domain %s",
1832				r->in.domain_name,
1833				get_friendly_nt_error_msg(status));
1834			return WERR_DCNOTFOUND;
1835		}
1836
1837		dc = strip_hostname(info->dc_unc);
1838		r->in.dc_name = talloc_strdup(mem_ctx, dc);
1839		W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1840	}
1841
1842	status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
1843	if (!NT_STATUS_IS_OK(status)) {
1844		libnet_join_set_error_string(mem_ctx, r,
1845			"failed to lookup DC info for domain '%s' over rpc: %s",
1846			r->in.domain_name, get_friendly_nt_error_msg(status));
1847		return ntstatus_to_werror(status);
1848	}
1849
1850	werr = libnet_join_check_config(mem_ctx, r);
1851	if (!W_ERROR_IS_OK(werr)) {
1852		goto done;
1853	}
1854
1855#ifdef WITH_ADS
1856	if (r->out.domain_is_ad && r->in.account_ou &&
1857	    !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1858
1859		ads_status = libnet_join_connect_ads(mem_ctx, r);
1860		if (!ADS_ERR_OK(ads_status)) {
1861			return WERR_DEFAULT_JOIN_REQUIRED;
1862		}
1863
1864		ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1865		if (!ADS_ERR_OK(ads_status)) {
1866			libnet_join_set_error_string(mem_ctx, r,
1867				"failed to precreate account in ou %s: %s",
1868				r->in.account_ou,
1869				ads_errstr(ads_status));
1870			return WERR_DEFAULT_JOIN_REQUIRED;
1871		}
1872
1873		r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1874	}
1875#endif /* WITH_ADS */
1876
1877	if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
1878	    (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
1879		status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
1880	} else {
1881		status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
1882	}
1883	if (!NT_STATUS_IS_OK(status)) {
1884		libnet_join_set_error_string(mem_ctx, r,
1885			"failed to join domain '%s' over rpc: %s",
1886			r->in.domain_name, get_friendly_nt_error_msg(status));
1887		if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1888			return WERR_SETUP_ALREADY_JOINED;
1889		}
1890		werr = ntstatus_to_werror(status);
1891		goto done;
1892	}
1893
1894	if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1895		werr = WERR_SETUP_NOT_JOINED;
1896		goto done;
1897	}
1898
1899	werr = WERR_OK;
1900
1901 done:
1902	if (cli) {
1903		cli_shutdown(cli);
1904	}
1905
1906	return werr;
1907}
1908
1909/****************************************************************
1910****************************************************************/
1911
1912static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
1913				   struct libnet_JoinCtx *r)
1914{
1915	WERROR werr;
1916	struct libnet_UnjoinCtx *u = NULL;
1917
1918	werr = libnet_init_UnjoinCtx(mem_ctx, &u);
1919	if (!W_ERROR_IS_OK(werr)) {
1920		return werr;
1921	}
1922
1923	u->in.debug		= r->in.debug;
1924	u->in.dc_name		= r->in.dc_name;
1925	u->in.domain_name	= r->in.domain_name;
1926	u->in.admin_account	= r->in.admin_account;
1927	u->in.admin_password	= r->in.admin_password;
1928	u->in.modify_config	= r->in.modify_config;
1929	u->in.unjoin_flags	= WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1930				  WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1931
1932	werr = libnet_Unjoin(mem_ctx, u);
1933	TALLOC_FREE(u);
1934
1935	return werr;
1936}
1937
1938/****************************************************************
1939****************************************************************/
1940
1941WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1942		   struct libnet_JoinCtx *r)
1943{
1944	WERROR werr;
1945
1946	if (r->in.debug) {
1947		LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
1948	}
1949
1950	werr = libnet_join_pre_processing(mem_ctx, r);
1951	if (!W_ERROR_IS_OK(werr)) {
1952		goto done;
1953	}
1954
1955	if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1956		werr = libnet_DomainJoin(mem_ctx, r);
1957		if (!W_ERROR_IS_OK(werr)) {
1958			goto done;
1959		}
1960	}
1961
1962	werr = libnet_join_post_processing(mem_ctx, r);
1963	if (!W_ERROR_IS_OK(werr)) {
1964		goto done;
1965	}
1966
1967	if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1968		werr = libnet_join_post_verify(mem_ctx, r);
1969		if (!W_ERROR_IS_OK(werr)) {
1970			libnet_join_rollback(mem_ctx, r);
1971		}
1972	}
1973
1974 done:
1975	r->out.result = werr;
1976
1977	if (r->in.debug) {
1978		LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
1979	}
1980	return werr;
1981}
1982
1983/****************************************************************
1984****************************************************************/
1985
1986static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1987				  struct libnet_UnjoinCtx *r)
1988{
1989	NTSTATUS status;
1990
1991	if (!r->in.domain_sid) {
1992		struct dom_sid sid;
1993		if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
1994			libnet_unjoin_set_error_string(mem_ctx, r,
1995				"Unable to fetch domain sid: are we joined?");
1996			return WERR_SETUP_NOT_JOINED;
1997		}
1998		r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid);
1999		W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2000	}
2001
2002	if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2003	    !r->in.delete_machine_account) {
2004		libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2005		return WERR_OK;
2006	}
2007
2008	if (!r->in.dc_name) {
2009		struct netr_DsRGetDCNameInfo *info;
2010		const char *dc;
2011		status = dsgetdcname(mem_ctx,
2012				     r->in.msg_ctx,
2013				     r->in.domain_name,
2014				     NULL,
2015				     NULL,
2016				     DS_DIRECTORY_SERVICE_REQUIRED |
2017				     DS_WRITABLE_REQUIRED |
2018				     DS_RETURN_DNS_NAME,
2019				     &info);
2020		if (!NT_STATUS_IS_OK(status)) {
2021			libnet_unjoin_set_error_string(mem_ctx, r,
2022				"failed to find DC for domain %s",
2023				r->in.domain_name,
2024				get_friendly_nt_error_msg(status));
2025			return WERR_DCNOTFOUND;
2026		}
2027
2028		dc = strip_hostname(info->dc_unc);
2029		r->in.dc_name = talloc_strdup(mem_ctx, dc);
2030		W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2031	}
2032
2033#ifdef WITH_ADS
2034	/* for net ads leave, try to delete the account.  If it works,
2035	   no sense in disabling.  If it fails, we can still try to
2036	   disable it. jmcd */
2037
2038	if (r->in.delete_machine_account) {
2039		ADS_STATUS ads_status;
2040		ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2041		if (ADS_ERR_OK(ads_status)) {
2042			/* dirty hack */
2043			r->out.dns_domain_name =
2044				talloc_strdup(mem_ctx,
2045					      r->in.ads->server.realm);
2046			ads_status =
2047				libnet_unjoin_remove_machine_acct(mem_ctx, r);
2048		}
2049		if (!ADS_ERR_OK(ads_status)) {
2050			libnet_unjoin_set_error_string(mem_ctx, r,
2051				"failed to remove machine account from AD: %s",
2052				ads_errstr(ads_status));
2053		} else {
2054			r->out.deleted_machine_account = true;
2055			W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2056			libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2057			return WERR_OK;
2058		}
2059	}
2060#endif /* WITH_ADS */
2061
2062	/* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2063	   "disable".  */
2064	if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2065		status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2066		if (!NT_STATUS_IS_OK(status)) {
2067			libnet_unjoin_set_error_string(mem_ctx, r,
2068				"failed to disable machine account via rpc: %s",
2069				get_friendly_nt_error_msg(status));
2070			if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2071				return WERR_SETUP_NOT_JOINED;
2072			}
2073			return ntstatus_to_werror(status);
2074		}
2075
2076		r->out.disabled_machine_account = true;
2077	}
2078
2079	/* If disable succeeded or was not requested at all, we
2080	   should be getting rid of our end of things */
2081
2082	libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2083
2084	return WERR_OK;
2085}
2086
2087/****************************************************************
2088****************************************************************/
2089
2090static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2091					   struct libnet_UnjoinCtx *r)
2092{
2093	if (!r->in.domain_name) {
2094		libnet_unjoin_set_error_string(mem_ctx, r,
2095			"No domain name defined");
2096		return WERR_INVALID_PARAM;
2097	}
2098
2099	if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2100				    &r->in.domain_name,
2101				    &r->in.dc_name)) {
2102		libnet_unjoin_set_error_string(mem_ctx, r,
2103			"Failed to parse domain name");
2104		return WERR_INVALID_PARAM;
2105	}
2106
2107	if (IS_DC) {
2108		return WERR_SETUP_DOMAIN_CONTROLLER;
2109	}
2110
2111	if (!secrets_init()) {
2112		libnet_unjoin_set_error_string(mem_ctx, r,
2113			"Unable to open secrets database");
2114		return WERR_CAN_NOT_COMPLETE;
2115	}
2116
2117	return WERR_OK;
2118}
2119
2120/****************************************************************
2121****************************************************************/
2122
2123static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2124					    struct libnet_UnjoinCtx *r)
2125{
2126	saf_delete(r->out.netbios_domain_name);
2127	saf_delete(r->out.dns_domain_name);
2128
2129	return libnet_unjoin_config(r);
2130}
2131
2132/****************************************************************
2133****************************************************************/
2134
2135WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2136		     struct libnet_UnjoinCtx *r)
2137{
2138	WERROR werr;
2139
2140	if (r->in.debug) {
2141		LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2142	}
2143
2144	werr = libnet_unjoin_pre_processing(mem_ctx, r);
2145	if (!W_ERROR_IS_OK(werr)) {
2146		goto done;
2147	}
2148
2149	if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2150		werr = libnet_DomainUnjoin(mem_ctx, r);
2151		if (!W_ERROR_IS_OK(werr)) {
2152			libnet_unjoin_config(r);
2153			goto done;
2154		}
2155	}
2156
2157	werr = libnet_unjoin_post_processing(mem_ctx, r);
2158	if (!W_ERROR_IS_OK(werr)) {
2159		goto done;
2160	}
2161
2162 done:
2163	r->out.result = werr;
2164
2165	if (r->in.debug) {
2166		LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2167	}
2168
2169	return werr;
2170}
2171