source: vendor/3.5.0/source3/libnet/libnet_join.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 52.9 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.