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

Last change on this file was 597, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update vendor to version 3.5.9

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