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

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 69.8 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 "ads.h"
23#include "librpc/gen_ndr/ndr_libnet_join.h"
24#include "libnet/libnet_join.h"
25#include "libcli/auth/libcli_auth.h"
26#include "../librpc/gen_ndr/ndr_samr_c.h"
27#include "rpc_client/init_samr.h"
28#include "../librpc/gen_ndr/ndr_lsa_c.h"
29#include "rpc_client/cli_lsarpc.h"
30#include "../librpc/gen_ndr/ndr_netlogon.h"
31#include "rpc_client/cli_netlogon.h"
32#include "lib/smbconf/smbconf.h"
33#include "lib/smbconf/smbconf_reg.h"
34#include "../libds/common/flags.h"
35#include "secrets.h"
36#include "rpc_client/init_lsa.h"
37#include "rpc_client/cli_pipe.h"
38#include "../libcli/security/security.h"
39#include "passdb.h"
40#include "libsmb/libsmb.h"
41#include "../libcli/smb/smbXcli_base.h"
42#include "lib/param/loadparm.h"
43#include "libcli/auth/netlogon_creds_cli.h"
44#include "auth/credentials/credentials.h"
45#include "krb5_env.h"
46
47/****************************************************************
48****************************************************************/
49
50#define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
51 do { \
52 char *str = NULL; \
53 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
54 DEBUG(1,("libnet_Join:\n%s", str)); \
55 TALLOC_FREE(str); \
56 } while (0)
57
58#define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
59 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
60#define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
61 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
62
63#define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
64 do { \
65 char *str = NULL; \
66 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
67 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
68 TALLOC_FREE(str); \
69 } while (0)
70
71#define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
72 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
73#define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
74 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
75
76/****************************************************************
77****************************************************************/
78
79static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
80 struct libnet_JoinCtx *r,
81 const char *format, ...)
82{
83 va_list args;
84
85 if (r->out.error_string) {
86 return;
87 }
88
89 va_start(args, format);
90 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
91 va_end(args);
92}
93
94/****************************************************************
95****************************************************************/
96
97static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
98 struct libnet_UnjoinCtx *r,
99 const char *format, ...)
100{
101 va_list args;
102
103 if (r->out.error_string) {
104 return;
105 }
106
107 va_start(args, format);
108 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
109 va_end(args);
110}
111
112#ifdef HAVE_ADS
113
114/****************************************************************
115****************************************************************/
116
117static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
118 const char *netbios_domain_name,
119 const char *dc_name,
120 const char *user_name,
121 const char *password,
122 const char *ccname,
123 ADS_STRUCT **ads)
124{
125 ADS_STATUS status;
126 ADS_STRUCT *my_ads = NULL;
127 char *cp;
128
129 my_ads = ads_init(dns_domain_name,
130 netbios_domain_name,
131 dc_name);
132 if (!my_ads) {
133 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
134 }
135
136 if (user_name) {
137 SAFE_FREE(my_ads->auth.user_name);
138 my_ads->auth.user_name = SMB_STRDUP(user_name);
139 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
140 *cp++ = '\0';
141 SAFE_FREE(my_ads->auth.realm);
142 my_ads->auth.realm = smb_xstrdup(cp);
143 if (!strupper_m(my_ads->auth.realm)) {
144 ads_destroy(&my_ads);
145 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
146 }
147 }
148 }
149
150 if (password) {
151 SAFE_FREE(my_ads->auth.password);
152 my_ads->auth.password = SMB_STRDUP(password);
153 }
154
155 if (ccname != NULL) {
156 SAFE_FREE(my_ads->auth.ccache_name);
157 my_ads->auth.ccache_name = SMB_STRDUP(ccname);
158 setenv(KRB5_ENV_CCNAME, my_ads->auth.ccache_name, 1);
159 }
160
161 status = ads_connect_user_creds(my_ads);
162 if (!ADS_ERR_OK(status)) {
163 ads_destroy(&my_ads);
164 return status;
165 }
166
167 *ads = my_ads;
168 return ADS_SUCCESS;
169}
170
171/****************************************************************
172****************************************************************/
173
174static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
175 struct libnet_JoinCtx *r,
176 bool use_machine_creds)
177{
178 ADS_STATUS status;
179 const char *username;
180 const char *password;
181 const char *ccname = NULL;
182
183 if (use_machine_creds) {
184 if (r->in.machine_name == NULL ||
185 r->in.machine_password == NULL) {
186 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
187 }
188 username = talloc_strdup(mem_ctx, r->in.machine_name);
189 if (username == NULL) {
190 return ADS_ERROR(LDAP_NO_MEMORY);
191 }
192 if (username[strlen(username)] != '$') {
193 username = talloc_asprintf(username, "%s$", username);
194 if (username == NULL) {
195 return ADS_ERROR(LDAP_NO_MEMORY);
196 }
197 }
198 password = r->in.machine_password;
199 ccname = "MEMORY:libnet_join_machine_creds";
200 } else {
201 username = r->in.admin_account;
202 password = r->in.admin_password;
203
204 /*
205 * when r->in.use_kerberos is set to allow "net ads join -k" we
206 * may not override the provided credential cache - gd
207 */
208
209 if (!r->in.use_kerberos) {
210 ccname = "MEMORY:libnet_join_user_creds";
211 }
212 }
213
214 status = libnet_connect_ads(r->out.dns_domain_name,
215 r->out.netbios_domain_name,
216 r->in.dc_name,
217 username,
218 password,
219 ccname,
220 &r->in.ads);
221 if (!ADS_ERR_OK(status)) {
222 libnet_join_set_error_string(mem_ctx, r,
223 "failed to connect to AD: %s",
224 ads_errstr(status));
225 return status;
226 }
227
228 if (!r->out.netbios_domain_name) {
229 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
230 r->in.ads->server.workgroup);
231 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
232 }
233
234 if (!r->out.dns_domain_name) {
235 r->out.dns_domain_name = talloc_strdup(mem_ctx,
236 r->in.ads->config.realm);
237 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
238 }
239
240 r->out.domain_is_ad = true;
241
242 return ADS_SUCCESS;
243}
244
245/****************************************************************
246****************************************************************/
247
248static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
249 struct libnet_JoinCtx *r)
250{
251 return libnet_join_connect_ads(mem_ctx, r, false);
252}
253
254/****************************************************************
255****************************************************************/
256
257static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
258 struct libnet_JoinCtx *r)
259{
260 return libnet_join_connect_ads(mem_ctx, r, true);
261}
262
263/****************************************************************
264****************************************************************/
265
266static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
267 struct libnet_UnjoinCtx *r)
268{
269 ADS_STATUS status;
270
271 status = libnet_connect_ads(r->in.domain_name,
272 r->in.domain_name,
273 r->in.dc_name,
274 r->in.admin_account,
275 r->in.admin_password,
276 NULL,
277 &r->in.ads);
278 if (!ADS_ERR_OK(status)) {
279 libnet_unjoin_set_error_string(mem_ctx, r,
280 "failed to connect to AD: %s",
281 ads_errstr(status));
282 }
283
284 return status;
285}
286
287/****************************************************************
288 join a domain using ADS (LDAP mods)
289****************************************************************/
290
291static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
292 struct libnet_JoinCtx *r)
293{
294 ADS_STATUS status;
295 LDAPMessage *res = NULL;
296 const char *attrs[] = { "dn", NULL };
297 bool moved = false;
298
299 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
300 if (!ADS_ERR_OK(status)) {
301 return status;
302 }
303
304 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
305 if (!ADS_ERR_OK(status)) {
306 return status;
307 }
308
309 if (ads_count_replies(r->in.ads, res) != 1) {
310 ads_msgfree(r->in.ads, res);
311 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
312 }
313
314 ads_msgfree(r->in.ads, res);
315
316 /* Attempt to create the machine account and bail if this fails.
317 Assume that the admin wants exactly what they requested */
318
319 status = ads_create_machine_acct(r->in.ads,
320 r->in.machine_name,
321 r->in.account_ou,
322 r->in.desired_encryption_types);
323
324 if (ADS_ERR_OK(status)) {
325 DEBUG(1,("machine account creation created\n"));
326 return status;
327 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
328 (status.err.rc == LDAP_ALREADY_EXISTS)) {
329 status = ADS_SUCCESS;
330 }
331
332 if (!ADS_ERR_OK(status)) {
333 DEBUG(1,("machine account creation failed\n"));
334 return status;
335 }
336
337 status = ads_move_machine_acct(r->in.ads,
338 r->in.machine_name,
339 r->in.account_ou,
340 &moved);
341 if (!ADS_ERR_OK(status)) {
342 DEBUG(1,("failure to locate/move pre-existing "
343 "machine account\n"));
344 return status;
345 }
346
347 DEBUG(1,("The machine account %s the specified OU.\n",
348 moved ? "was moved into" : "already exists in"));
349
350 return status;
351}
352
353/****************************************************************
354****************************************************************/
355
356static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
357 struct libnet_UnjoinCtx *r)
358{
359 ADS_STATUS status;
360
361 if (!r->in.ads) {
362 status = libnet_unjoin_connect_ads(mem_ctx, r);
363 if (!ADS_ERR_OK(status)) {
364 libnet_unjoin_set_error_string(mem_ctx, r,
365 "failed to connect to AD: %s",
366 ads_errstr(status));
367 return status;
368 }
369 }
370
371 status = ads_leave_realm(r->in.ads, r->in.machine_name);
372 if (!ADS_ERR_OK(status)) {
373 libnet_unjoin_set_error_string(mem_ctx, r,
374 "failed to leave realm: %s",
375 ads_errstr(status));
376 return status;
377 }
378
379 return ADS_SUCCESS;
380}
381
382/****************************************************************
383****************************************************************/
384
385static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
386 struct libnet_JoinCtx *r)
387{
388 ADS_STATUS status;
389 LDAPMessage *res = NULL;
390 char *dn = NULL;
391
392 if (!r->in.machine_name) {
393 return ADS_ERROR(LDAP_NO_MEMORY);
394 }
395
396 status = ads_find_machine_acct(r->in.ads,
397 &res,
398 r->in.machine_name);
399 if (!ADS_ERR_OK(status)) {
400 return status;
401 }
402
403 if (ads_count_replies(r->in.ads, res) != 1) {
404 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
405 goto done;
406 }
407
408 dn = ads_get_dn(r->in.ads, mem_ctx, res);
409 if (!dn) {
410 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
411 goto done;
412 }
413
414 r->out.dn = talloc_strdup(mem_ctx, dn);
415 if (!r->out.dn) {
416 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
417 goto done;
418 }
419
420 if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
421 &r->out.set_encryption_types)) {
422 r->out.set_encryption_types = 0;
423 }
424
425 done:
426 ads_msgfree(r->in.ads, res);
427 TALLOC_FREE(dn);
428
429 return status;
430}
431
432static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx,
433 struct libnet_JoinCtx *r,
434 char ***spn_array,
435 size_t *num_spns)
436{
437 ADS_STATUS status;
438
439 if (r->in.machine_name == NULL) {
440 return ADS_ERROR_SYSTEM(EINVAL);
441 }
442
443 status = ads_get_service_principal_names(mem_ctx,
444 r->in.ads,
445 r->in.machine_name,
446 spn_array,
447 num_spns);
448
449 return status;
450}
451
452/****************************************************************
453 Set a machines dNSHostName and servicePrincipalName attributes
454****************************************************************/
455
456static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
457 struct libnet_JoinCtx *r)
458{
459 ADS_STATUS status;
460 ADS_MODLIST mods;
461 fstring my_fqdn;
462 const char **spn_array = NULL;
463 size_t num_spns = 0;
464 char *spn = NULL;
465 bool ok;
466 const char **netbios_aliases = NULL;
467
468 /* Find our DN */
469
470 status = libnet_join_find_machine_acct(mem_ctx, r);
471 if (!ADS_ERR_OK(status)) {
472 return status;
473 }
474
475 status = libnet_join_get_machine_spns(mem_ctx,
476 r,
477 discard_const_p(char **, &spn_array),
478 &num_spns);
479 if (!ADS_ERR_OK(status)) {
480 DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
481 }
482
483 /* Windows only creates HOST/shortname & HOST/fqdn. */
484
485 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
486 if (!spn) {
487 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
488 }
489 if (!strupper_m(spn)) {
490 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
491 }
492
493 ok = ads_element_in_array(spn_array, num_spns, spn);
494 if (!ok) {
495 ok = add_string_to_array(spn_array, spn,
496 &spn_array, &num_spns);
497 if (!ok) {
498 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
499 }
500 }
501
502 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
503 || (strchr(my_fqdn, '.') == NULL)) {
504 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
505 r->out.dns_domain_name);
506 }
507
508 if (!strlower_m(my_fqdn)) {
509 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
510 }
511
512 if (!strequal(my_fqdn, r->in.machine_name)) {
513 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
514 if (!spn) {
515 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
516 }
517
518 ok = ads_element_in_array(spn_array, num_spns, spn);
519 if (!ok) {
520 ok = add_string_to_array(spn_array, spn,
521 &spn_array, &num_spns);
522 if (!ok) {
523 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
524 }
525 }
526 }
527
528 netbios_aliases = lp_netbios_aliases();
529 if (netbios_aliases != NULL) {
530 for (; *netbios_aliases != NULL; netbios_aliases++) {
531 /*
532 * Add HOST/NETBIOSNAME
533 */
534 spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases);
535 if (spn == NULL) {
536 TALLOC_FREE(spn);
537 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
538 }
539 if (!strupper_m(spn)) {
540 TALLOC_FREE(spn);
541 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
542 }
543
544 ok = ads_element_in_array(spn_array, num_spns, spn);
545 if (ok) {
546 TALLOC_FREE(spn);
547 continue;
548 }
549 ok = add_string_to_array(spn_array, spn,
550 &spn_array, &num_spns);
551 if (!ok) {
552 TALLOC_FREE(spn);
553 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
554 }
555 TALLOC_FREE(spn);
556
557 /*
558 * Add HOST/netbiosname.domainname
559 */
560 if (r->out.dns_domain_name == NULL) {
561 continue;
562 }
563 fstr_sprintf(my_fqdn, "%s.%s",
564 *netbios_aliases,
565 r->out.dns_domain_name);
566
567 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
568 if (spn == NULL) {
569 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
570 }
571
572 ok = ads_element_in_array(spn_array, num_spns, spn);
573 if (ok) {
574 TALLOC_FREE(spn);
575 continue;
576 }
577 ok = add_string_to_array(spn_array, spn,
578 &spn_array, &num_spns);
579 if (!ok) {
580 TALLOC_FREE(spn);
581 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
582 }
583 TALLOC_FREE(spn);
584 }
585 }
586
587 /* make sure to NULL terminate the array */
588 spn_array = talloc_realloc(mem_ctx, spn_array, const char *, num_spns + 1);
589 if (spn_array == NULL) {
590 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
591 }
592 spn_array[num_spns] = NULL;
593
594 mods = ads_init_mods(mem_ctx);
595 if (!mods) {
596 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
597 }
598
599 /* fields of primary importance */
600
601 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
602 if (!ADS_ERR_OK(status)) {
603 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
604 }
605
606 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
607 spn_array);
608 if (!ADS_ERR_OK(status)) {
609 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
610 }
611
612 return ads_gen_mod(r->in.ads, r->out.dn, mods);
613}
614
615/****************************************************************
616****************************************************************/
617
618static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
619 struct libnet_JoinCtx *r)
620{
621 ADS_STATUS status;
622 ADS_MODLIST mods;
623
624 if (!r->in.create_upn) {
625 return ADS_SUCCESS;
626 }
627
628 /* Find our DN */
629
630 status = libnet_join_find_machine_acct(mem_ctx, r);
631 if (!ADS_ERR_OK(status)) {
632 return status;
633 }
634
635 if (!r->in.upn) {
636 const char *realm = r->out.dns_domain_name;
637
638 /* in case we are about to generate a keytab during the join
639 * make sure the default upn we create is usable with kinit -k.
640 * gd */
641
642 if (USE_KERBEROS_KEYTAB) {
643 realm = talloc_strdup_upper(mem_ctx,
644 r->out.dns_domain_name);
645 }
646
647 if (!realm) {
648 return ADS_ERROR(LDAP_NO_MEMORY);
649 }
650
651 r->in.upn = talloc_asprintf(mem_ctx,
652 "host/%s@%s",
653 r->in.machine_name,
654 realm);
655 if (!r->in.upn) {
656 return ADS_ERROR(LDAP_NO_MEMORY);
657 }
658 }
659
660 /* now do the mods */
661
662 mods = ads_init_mods(mem_ctx);
663 if (!mods) {
664 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
665 }
666
667 /* fields of primary importance */
668
669 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
670 if (!ADS_ERR_OK(status)) {
671 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
672 }
673
674 return ads_gen_mod(r->in.ads, r->out.dn, mods);
675}
676
677
678/****************************************************************
679****************************************************************/
680
681static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
682 struct libnet_JoinCtx *r)
683{
684 ADS_STATUS status;
685 ADS_MODLIST mods;
686 char *os_sp = NULL;
687
688 if (!r->in.os_name || !r->in.os_version ) {
689 return ADS_SUCCESS;
690 }
691
692 /* Find our DN */
693
694 status = libnet_join_find_machine_acct(mem_ctx, r);
695 if (!ADS_ERR_OK(status)) {
696 return status;
697 }
698
699 /* now do the mods */
700
701 mods = ads_init_mods(mem_ctx);
702 if (!mods) {
703 return ADS_ERROR(LDAP_NO_MEMORY);
704 }
705
706 if (r->in.os_servicepack) {
707 /*
708 * if blank string then leave os_sp equal to NULL to force
709 * attribute delete (LDAP_MOD_DELETE)
710 */
711 if (!strequal(r->in.os_servicepack,"")) {
712 os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
713 }
714 } else {
715 os_sp = talloc_asprintf(mem_ctx, "Samba %s",
716 samba_version_string());
717 }
718 if (!os_sp && !strequal(r->in.os_servicepack,"")) {
719 return ADS_ERROR(LDAP_NO_MEMORY);
720 }
721
722 /* fields of primary importance */
723
724 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
725 r->in.os_name);
726 if (!ADS_ERR_OK(status)) {
727 return status;
728 }
729
730 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
731 r->in.os_version);
732 if (!ADS_ERR_OK(status)) {
733 return status;
734 }
735
736 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
737 os_sp);
738 if (!ADS_ERR_OK(status)) {
739 return status;
740 }
741
742 return ads_gen_mod(r->in.ads, r->out.dn, mods);
743}
744
745/****************************************************************
746****************************************************************/
747
748static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
749 struct libnet_JoinCtx *r)
750{
751 ADS_STATUS status;
752 ADS_MODLIST mods;
753 const char *etype_list_str;
754
755 etype_list_str = talloc_asprintf(mem_ctx, "%d",
756 r->in.desired_encryption_types);
757 if (!etype_list_str) {
758 return ADS_ERROR(LDAP_NO_MEMORY);
759 }
760
761 /* Find our DN */
762
763 status = libnet_join_find_machine_acct(mem_ctx, r);
764 if (!ADS_ERR_OK(status)) {
765 return status;
766 }
767
768 if (r->in.desired_encryption_types == r->out.set_encryption_types) {
769 return ADS_SUCCESS;
770 }
771
772 /* now do the mods */
773
774 mods = ads_init_mods(mem_ctx);
775 if (!mods) {
776 return ADS_ERROR(LDAP_NO_MEMORY);
777 }
778
779 status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
780 etype_list_str);
781 if (!ADS_ERR_OK(status)) {
782 return status;
783 }
784
785 status = ads_gen_mod(r->in.ads, r->out.dn, mods);
786 if (!ADS_ERR_OK(status)) {
787 return status;
788 }
789
790 r->out.set_encryption_types = r->in.desired_encryption_types;
791
792 return ADS_SUCCESS;
793}
794
795/****************************************************************
796****************************************************************/
797
798static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
799 struct libnet_JoinCtx *r)
800{
801 if (!USE_SYSTEM_KEYTAB) {
802 return true;
803 }
804
805 if (ads_keytab_create_default(r->in.ads) != 0) {
806 return false;
807 }
808
809 return true;
810}
811
812/****************************************************************
813****************************************************************/
814
815static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
816 struct libnet_JoinCtx *r)
817{
818 uint32_t domain_func;
819 ADS_STATUS status;
820 const char *salt = NULL;
821 char *std_salt = NULL;
822
823 status = ads_domain_func_level(r->in.ads, &domain_func);
824 if (!ADS_ERR_OK(status)) {
825 libnet_join_set_error_string(mem_ctx, r,
826 "failed to determine domain functional level: %s",
827 ads_errstr(status));
828 return false;
829 }
830
831 /* go ahead and setup the default salt */
832
833 std_salt = kerberos_standard_des_salt();
834 if (!std_salt) {
835 libnet_join_set_error_string(mem_ctx, r,
836 "failed to obtain standard DES salt");
837 return false;
838 }
839
840 salt = talloc_strdup(mem_ctx, std_salt);
841 if (!salt) {
842 return false;
843 }
844
845 SAFE_FREE(std_salt);
846
847 /* if it's a Windows functional domain, we have to look for the UPN */
848
849 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
850 char *upn;
851
852 upn = ads_get_upn(r->in.ads, mem_ctx,
853 r->in.machine_name);
854 if (upn) {
855 salt = talloc_strdup(mem_ctx, upn);
856 if (!salt) {
857 return false;
858 }
859 }
860 }
861
862 return kerberos_secrets_store_des_salt(salt);
863}
864
865/****************************************************************
866****************************************************************/
867
868static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
869 struct libnet_JoinCtx *r)
870{
871 ADS_STATUS status;
872 bool need_etype_update = false;
873
874 if (!r->in.ads) {
875 status = libnet_join_connect_ads_user(mem_ctx, r);
876 if (!ADS_ERR_OK(status)) {
877 return status;
878 }
879 }
880
881 status = libnet_join_set_machine_spn(mem_ctx, r);
882 if (!ADS_ERR_OK(status)) {
883 libnet_join_set_error_string(mem_ctx, r,
884 "Failed to set machine spn: %s\n"
885 "Do you have sufficient permissions to create machine "
886 "accounts?",
887 ads_errstr(status));
888 return status;
889 }
890
891 status = libnet_join_set_os_attributes(mem_ctx, r);
892 if (!ADS_ERR_OK(status)) {
893 libnet_join_set_error_string(mem_ctx, r,
894 "failed to set machine os attributes: %s",
895 ads_errstr(status));
896 return status;
897 }
898
899 status = libnet_join_set_machine_upn(mem_ctx, r);
900 if (!ADS_ERR_OK(status)) {
901 libnet_join_set_error_string(mem_ctx, r,
902 "failed to set machine upn: %s",
903 ads_errstr(status));
904 return status;
905 }
906
907 status = libnet_join_find_machine_acct(mem_ctx, r);
908 if (!ADS_ERR_OK(status)) {
909 return status;
910 }
911
912 if (r->in.desired_encryption_types != r->out.set_encryption_types) {
913 uint32_t func_level = 0;
914
915 status = ads_domain_func_level(r->in.ads, &func_level);
916 if (!ADS_ERR_OK(status)) {
917 libnet_join_set_error_string(mem_ctx, r,
918 "failed to query domain controller functional level: %s",
919 ads_errstr(status));
920 return status;
921 }
922
923 if (func_level >= DS_DOMAIN_FUNCTION_2008) {
924 need_etype_update = true;
925 }
926 }
927
928 if (need_etype_update) {
929 /*
930 * We need to reconnect as machine account in order
931 * to update msDS-SupportedEncryptionTypes reliable
932 */
933
934 if (r->in.ads->auth.ccache_name != NULL) {
935 ads_kdestroy(r->in.ads->auth.ccache_name);
936 }
937
938 ads_destroy(&r->in.ads);
939
940 status = libnet_join_connect_ads_machine(mem_ctx, r);
941 if (!ADS_ERR_OK(status)) {
942 libnet_join_set_error_string(mem_ctx, r,
943 "Failed to connect as machine account: %s",
944 ads_errstr(status));
945 return status;
946 }
947
948 status = libnet_join_set_etypes(mem_ctx, r);
949 if (!ADS_ERR_OK(status)) {
950 libnet_join_set_error_string(mem_ctx, r,
951 "failed to set machine kerberos encryption types: %s",
952 ads_errstr(status));
953 return status;
954 }
955 }
956
957 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
958 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
959 }
960
961 if (!libnet_join_create_keytab(mem_ctx, r)) {
962 libnet_join_set_error_string(mem_ctx, r,
963 "failed to create kerberos keytab");
964 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
965 }
966
967 return ADS_SUCCESS;
968}
969#endif /* HAVE_ADS */
970
971/****************************************************************
972 Store the machine password and domain SID
973****************************************************************/
974
975static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
976 struct libnet_JoinCtx *r)
977{
978 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
979 r->out.domain_sid))
980 {
981 DEBUG(1,("Failed to save domain sid\n"));
982 return false;
983 }
984
985 if (!secrets_store_machine_password(r->in.machine_password,
986 r->out.netbios_domain_name,
987 r->in.secure_channel_type))
988 {
989 DEBUG(1,("Failed to save machine password\n"));
990 return false;
991 }
992
993 return true;
994}
995
996/****************************************************************
997 Connect dc's IPC$ share
998****************************************************************/
999
1000static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
1001 const char *user,
1002 const char *domain,
1003 const char *pass,
1004 bool use_kerberos,
1005 struct cli_state **cli)
1006{
1007 int flags = 0;
1008
1009 if (use_kerberos) {
1010 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1011 }
1012
1013 if (use_kerberos && pass) {
1014 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
1015 }
1016
1017 return cli_full_connection(cli, NULL,
1018 dc,
1019 NULL, 0,
1020 "IPC$", "IPC",
1021 user,
1022 domain,
1023 pass,
1024 flags,
1025 SMB_SIGNING_IPC_DEFAULT);
1026}
1027
1028/****************************************************************
1029 Lookup domain dc's info
1030****************************************************************/
1031
1032static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1033 struct libnet_JoinCtx *r,
1034 struct cli_state **cli)
1035{
1036 struct rpc_pipe_client *pipe_hnd = NULL;
1037 struct policy_handle lsa_pol;
1038 NTSTATUS status, result;
1039 union lsa_PolicyInformation *info = NULL;
1040 struct dcerpc_binding_handle *b;
1041
1042 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1043 r->in.admin_account,
1044 r->in.admin_domain,
1045 r->in.admin_password,
1046 r->in.use_kerberos,
1047 cli);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 goto done;
1050 }
1051
1052 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1053 &pipe_hnd);
1054 if (!NT_STATUS_IS_OK(status)) {
1055 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
1056 nt_errstr(status)));
1057 goto done;
1058 }
1059
1060 b = pipe_hnd->binding_handle;
1061
1062 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1063 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1064 if (!NT_STATUS_IS_OK(status)) {
1065 goto done;
1066 }
1067
1068 status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1069 &lsa_pol,
1070 LSA_POLICY_INFO_DNS,
1071 &info,
1072 &result);
1073 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1074 r->out.domain_is_ad = true;
1075 r->out.netbios_domain_name = info->dns.name.string;
1076 r->out.dns_domain_name = info->dns.dns_domain.string;
1077 r->out.forest_name = info->dns.dns_forest.string;
1078 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1079 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1080 }
1081
1082 if (!NT_STATUS_IS_OK(status)) {
1083 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1084 &lsa_pol,
1085 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1086 &info,
1087 &result);
1088 if (!NT_STATUS_IS_OK(status)) {
1089 goto done;
1090 }
1091 if (!NT_STATUS_IS_OK(result)) {
1092 status = result;
1093 goto done;
1094 }
1095
1096 r->out.netbios_domain_name = info->account_domain.name.string;
1097 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1098 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1099 }
1100
1101 dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1102 TALLOC_FREE(pipe_hnd);
1103
1104 done:
1105 return status;
1106}
1107
1108/****************************************************************
1109 Do the domain join unsecure
1110****************************************************************/
1111
1112static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1113 struct libnet_JoinCtx *r,
1114 struct cli_state *cli)
1115{
1116 TALLOC_CTX *frame = talloc_stackframe();
1117 struct rpc_pipe_client *netlogon_pipe = NULL;
1118 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1119 struct samr_Password current_nt_hash;
1120 const char *account_name = NULL;
1121 NTSTATUS status;
1122
1123 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
1124 &netlogon_pipe);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 TALLOC_FREE(frame);
1127 return status;
1128 }
1129
1130 if (!r->in.machine_password) {
1131 r->in.machine_password = generate_random_password(mem_ctx,
1132 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
1133 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1134 if (r->in.machine_password == NULL) {
1135 TALLOC_FREE(frame);
1136 return NT_STATUS_NO_MEMORY;
1137 }
1138 }
1139
1140 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
1141 E_md4hash(r->in.admin_password, current_nt_hash.hash);
1142
1143 account_name = talloc_asprintf(frame, "%s$",
1144 r->in.machine_name);
1145 if (account_name == NULL) {
1146 TALLOC_FREE(frame);
1147 return NT_STATUS_NO_MEMORY;
1148 }
1149
1150 status = rpccli_create_netlogon_creds(netlogon_pipe->desthost,
1151 r->in.domain_name,
1152 account_name,
1153 r->in.secure_channel_type,
1154 r->in.msg_ctx,
1155 frame,
1156 &netlogon_creds);
1157 if (!NT_STATUS_IS_OK(status)) {
1158 TALLOC_FREE(frame);
1159 return status;
1160 }
1161
1162 status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
1163 netlogon_creds,
1164 true, /* force_reauth */
1165 current_nt_hash,
1166 NULL); /* previous_nt_hash */
1167 if (!NT_STATUS_IS_OK(status)) {
1168 TALLOC_FREE(frame);
1169 return status;
1170 }
1171
1172 status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1173 netlogon_pipe->binding_handle,
1174 r->in.machine_password,
1175 NULL); /* new_version */
1176 if (!NT_STATUS_IS_OK(status)) {
1177 TALLOC_FREE(frame);
1178 return status;
1179 }
1180
1181 TALLOC_FREE(frame);
1182 return NT_STATUS_OK;
1183}
1184
1185/****************************************************************
1186 Do the domain join
1187****************************************************************/
1188
1189static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1190 struct libnet_JoinCtx *r,
1191 struct cli_state *cli)
1192{
1193 struct rpc_pipe_client *pipe_hnd = NULL;
1194 struct policy_handle sam_pol, domain_pol, user_pol;
1195 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1196 char *acct_name;
1197 struct lsa_String lsa_acct_name;
1198 uint32_t user_rid;
1199 uint32_t acct_flags = ACB_WSTRUST;
1200 struct samr_Ids user_rids;
1201 struct samr_Ids name_types;
1202 union samr_UserInfo user_info;
1203 struct dcerpc_binding_handle *b = NULL;
1204 unsigned int old_timeout = 0;
1205
1206 DATA_BLOB session_key = data_blob_null;
1207 struct samr_CryptPassword crypt_pwd;
1208 struct samr_CryptPasswordEx crypt_pwd_ex;
1209
1210 ZERO_STRUCT(sam_pol);
1211 ZERO_STRUCT(domain_pol);
1212 ZERO_STRUCT(user_pol);
1213
1214 switch (r->in.secure_channel_type) {
1215 case SEC_CHAN_WKSTA:
1216 acct_flags = ACB_WSTRUST;
1217 break;
1218 case SEC_CHAN_BDC:
1219 acct_flags = ACB_SVRTRUST;
1220 break;
1221 default:
1222 return NT_STATUS_INVALID_PARAMETER;
1223 }
1224
1225 if (!r->in.machine_password) {
1226 r->in.machine_password = generate_random_password(mem_ctx,
1227 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
1228 DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
1229 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1230 }
1231
1232 /* Open the domain */
1233
1234 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1235 &pipe_hnd);
1236 if (!NT_STATUS_IS_OK(status)) {
1237 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1238 nt_errstr(status)));
1239 goto done;
1240 }
1241
1242 b = pipe_hnd->binding_handle;
1243
1244 status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1247 nt_errstr(status)));
1248 goto done;
1249 }
1250
1251 status = dcerpc_samr_Connect2(b, mem_ctx,
1252 pipe_hnd->desthost,
1253 SAMR_ACCESS_ENUM_DOMAINS
1254 | SAMR_ACCESS_LOOKUP_DOMAIN,
1255 &sam_pol,
1256 &result);
1257 if (!NT_STATUS_IS_OK(status)) {
1258 goto done;
1259 }
1260 if (!NT_STATUS_IS_OK(result)) {
1261 status = result;
1262 goto done;
1263 }
1264
1265 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1266 &sam_pol,
1267 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1268 | SAMR_DOMAIN_ACCESS_CREATE_USER
1269 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1270 r->out.domain_sid,
1271 &domain_pol,
1272 &result);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 goto done;
1275 }
1276 if (!NT_STATUS_IS_OK(result)) {
1277 status = result;
1278 goto done;
1279 }
1280
1281 /* Create domain user */
1282
1283 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1284 if (!strlower_m(acct_name)) {
1285 status = NT_STATUS_INVALID_PARAMETER;
1286 goto done;
1287 }
1288
1289 init_lsa_String(&lsa_acct_name, acct_name);
1290
1291 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1292 uint32_t access_desired =
1293 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1294 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1295 SAMR_USER_ACCESS_SET_PASSWORD |
1296 SAMR_USER_ACCESS_GET_ATTRIBUTES |
1297 SAMR_USER_ACCESS_SET_ATTRIBUTES;
1298 uint32_t access_granted = 0;
1299
1300 DEBUG(10,("Creating account with desired access mask: %d\n",
1301 access_desired));
1302
1303 status = dcerpc_samr_CreateUser2(b, mem_ctx,
1304 &domain_pol,
1305 &lsa_acct_name,
1306 acct_flags,
1307 access_desired,
1308 &user_pol,
1309 &access_granted,
1310 &user_rid,
1311 &result);
1312 if (!NT_STATUS_IS_OK(status)) {
1313 goto done;
1314 }
1315
1316 status = result;
1317 if (!NT_STATUS_IS_OK(status) &&
1318 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1319
1320 DEBUG(10,("Creation of workstation account failed: %s\n",
1321 nt_errstr(status)));
1322
1323 /* If NT_STATUS_ACCESS_DENIED then we have a valid
1324 username/password combo but the user does not have
1325 administrator access. */
1326
1327 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1328 libnet_join_set_error_string(mem_ctx, r,
1329 "User specified does not have "
1330 "administrator privileges");
1331 }
1332
1333 goto done;
1334 }
1335
1336 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1337 if (!(r->in.join_flags &
1338 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1339 goto done;
1340 }
1341 }
1342
1343 /* We *must* do this.... don't ask... */
1344
1345 if (NT_STATUS_IS_OK(status)) {
1346 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1347 }
1348 }
1349
1350 status = dcerpc_samr_LookupNames(b, mem_ctx,
1351 &domain_pol,
1352 1,
1353 &lsa_acct_name,
1354 &user_rids,
1355 &name_types,
1356 &result);
1357 if (!NT_STATUS_IS_OK(status)) {
1358 goto done;
1359 }
1360 if (!NT_STATUS_IS_OK(result)) {
1361 status = result;
1362 goto done;
1363 }
1364 if (user_rids.count != 1) {
1365 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1366 goto done;
1367 }
1368 if (name_types.count != 1) {
1369 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1370 goto done;
1371 }
1372
1373 if (name_types.ids[0] != SID_NAME_USER) {
1374 DEBUG(0,("%s is not a user account (type=%d)\n",
1375 acct_name, name_types.ids[0]));
1376 status = NT_STATUS_INVALID_WORKSTATION;
1377 goto done;
1378 }
1379
1380 user_rid = user_rids.ids[0];
1381
1382 /* Open handle on user */
1383
1384 status = dcerpc_samr_OpenUser(b, mem_ctx,
1385 &domain_pol,
1386 SEC_FLAG_MAXIMUM_ALLOWED,
1387 user_rid,
1388 &user_pol,
1389 &result);
1390 if (!NT_STATUS_IS_OK(status)) {
1391 goto done;
1392 }
1393 if (!NT_STATUS_IS_OK(result)) {
1394 status = result;
1395 goto done;
1396 }
1397
1398 /* Fill in the additional account flags now */
1399
1400 acct_flags |= ACB_PWNOEXP;
1401
1402 /* Set account flags on machine account */
1403 ZERO_STRUCT(user_info.info16);
1404 user_info.info16.acct_flags = acct_flags;
1405
1406 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1407 &user_pol,
1408 16,
1409 &user_info,
1410 &result);
1411 if (!NT_STATUS_IS_OK(status)) {
1412 dcerpc_samr_DeleteUser(b, mem_ctx,
1413 &user_pol,
1414 &result);
1415
1416 libnet_join_set_error_string(mem_ctx, r,
1417 "Failed to set account flags for machine account (%s)\n",
1418 nt_errstr(status));
1419 goto done;
1420 }
1421
1422 if (!NT_STATUS_IS_OK(result)) {
1423 status = result;
1424
1425 dcerpc_samr_DeleteUser(b, mem_ctx,
1426 &user_pol,
1427 &result);
1428
1429 libnet_join_set_error_string(mem_ctx, r,
1430 "Failed to set account flags for machine account (%s)\n",
1431 nt_errstr(status));
1432 goto done;
1433 }
1434
1435 /* Set password on machine account - first try level 26 */
1436
1437 /*
1438 * increase the timeout as password filter modules on the DC
1439 * might delay the operation for a significant amount of time
1440 */
1441 old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1442
1443 init_samr_CryptPasswordEx(r->in.machine_password,
1444 &session_key,
1445 &crypt_pwd_ex);
1446
1447 user_info.info26.password = crypt_pwd_ex;
1448 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1449
1450 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1451 &user_pol,
1452 26,
1453 &user_info,
1454 &result);
1455
1456 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1457
1458 /* retry with level 24 */
1459
1460 init_samr_CryptPassword(r->in.machine_password,
1461 &session_key,
1462 &crypt_pwd);
1463
1464 user_info.info24.password = crypt_pwd;
1465 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1466
1467 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1468 &user_pol,
1469 24,
1470 &user_info,
1471 &result);
1472 }
1473
1474 old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1475
1476 if (!NT_STATUS_IS_OK(status)) {
1477
1478 dcerpc_samr_DeleteUser(b, mem_ctx,
1479 &user_pol,
1480 &result);
1481
1482 libnet_join_set_error_string(mem_ctx, r,
1483 "Failed to set password for machine account (%s)\n",
1484 nt_errstr(status));
1485 goto done;
1486 }
1487 if (!NT_STATUS_IS_OK(result)) {
1488 status = result;
1489
1490 dcerpc_samr_DeleteUser(b, mem_ctx,
1491 &user_pol,
1492 &result);
1493
1494 libnet_join_set_error_string(mem_ctx, r,
1495 "Failed to set password for machine account (%s)\n",
1496 nt_errstr(status));
1497 goto done;
1498 }
1499
1500 status = NT_STATUS_OK;
1501
1502 done:
1503 if (!pipe_hnd) {
1504 return status;
1505 }
1506
1507 data_blob_clear_free(&session_key);
1508
1509 if (is_valid_policy_hnd(&sam_pol)) {
1510 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1511 }
1512 if (is_valid_policy_hnd(&domain_pol)) {
1513 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1514 }
1515 if (is_valid_policy_hnd(&user_pol)) {
1516 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1517 }
1518 TALLOC_FREE(pipe_hnd);
1519
1520 return status;
1521}
1522
1523/****************************************************************
1524****************************************************************/
1525
1526NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1527 const char *netbios_domain_name,
1528 const char *dc_name,
1529 const bool use_kerberos)
1530{
1531 TALLOC_CTX *frame = talloc_stackframe();
1532 struct cli_state *cli = NULL;
1533 struct rpc_pipe_client *netlogon_pipe = NULL;
1534 struct cli_credentials *cli_creds = NULL;
1535 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1536 struct netlogon_creds_CredentialState *creds = NULL;
1537 uint32_t netlogon_flags = 0;
1538 NTSTATUS status;
1539 const char *machine_account = NULL;
1540 const char *machine_domain = NULL;
1541 const char *machine_password = NULL;
1542 int flags = 0;
1543
1544 if (!dc_name) {
1545 TALLOC_FREE(frame);
1546 return NT_STATUS_INVALID_PARAMETER;
1547 }
1548
1549 if (!secrets_init()) {
1550 TALLOC_FREE(frame);
1551 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1552 }
1553
1554 status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1555 frame, &cli_creds);
1556 if (!NT_STATUS_IS_OK(status)) {
1557 TALLOC_FREE(frame);
1558 return status;
1559 }
1560
1561 /* we don't want any old password */
1562 cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1563
1564 if (use_kerberos) {
1565 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1566 }
1567
1568 machine_account = cli_credentials_get_username(cli_creds);
1569 machine_domain = cli_credentials_get_domain(cli_creds);
1570 machine_password = cli_credentials_get_password(cli_creds);
1571
1572 status = cli_full_connection(&cli, NULL,
1573 dc_name,
1574 NULL, 0,
1575 "IPC$", "IPC",
1576 machine_account,
1577 machine_domain,
1578 machine_password,
1579 flags,
1580 SMB_SIGNING_IPC_DEFAULT);
1581
1582 if (!NT_STATUS_IS_OK(status)) {
1583 status = cli_full_connection(&cli, NULL,
1584 dc_name,
1585 NULL, 0,
1586 "IPC$", "IPC",
1587 "",
1588 NULL,
1589 "",
1590 0,
1591 SMB_SIGNING_IPC_DEFAULT);
1592 }
1593
1594 if (!NT_STATUS_IS_OK(status)) {
1595 TALLOC_FREE(frame);
1596 return status;
1597 }
1598
1599 status = rpccli_create_netlogon_creds_with_creds(cli_creds,
1600 dc_name,
1601 msg_ctx,
1602 frame,
1603 &netlogon_creds);
1604 if (!NT_STATUS_IS_OK(status)) {
1605 cli_shutdown(cli);
1606 TALLOC_FREE(frame);
1607 return status;
1608 }
1609
1610 status = rpccli_setup_netlogon_creds_with_creds(cli, NCACN_NP,
1611 netlogon_creds,
1612 true, /* force_reauth */
1613 cli_creds);
1614 if (!NT_STATUS_IS_OK(status)) {
1615 DEBUG(0,("connect_to_domain_password_server: "
1616 "unable to open the domain client session to "
1617 "machine %s. Flags[0x%08X] Error was : %s.\n",
1618 dc_name, (unsigned)netlogon_flags,
1619 nt_errstr(status)));
1620 cli_shutdown(cli);
1621 TALLOC_FREE(frame);
1622 return status;
1623 }
1624
1625 status = netlogon_creds_cli_get(netlogon_creds,
1626 talloc_tos(),
1627 &creds);
1628 if (!NT_STATUS_IS_OK(status)) {
1629 cli_shutdown(cli);
1630 TALLOC_FREE(frame);
1631 return status;
1632 }
1633 netlogon_flags = creds->negotiate_flags;
1634 TALLOC_FREE(creds);
1635
1636 if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1637 cli_shutdown(cli);
1638 TALLOC_FREE(frame);
1639 return NT_STATUS_OK;
1640 }
1641
1642 status = cli_rpc_pipe_open_schannel_with_creds(
1643 cli, &ndr_table_netlogon, NCACN_NP,
1644 cli_creds,
1645 netlogon_creds, &netlogon_pipe);
1646
1647 TALLOC_FREE(netlogon_pipe);
1648
1649 if (!NT_STATUS_IS_OK(status)) {
1650 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1651 "on netlogon pipe to server %s for domain %s. "
1652 "Error was %s\n",
1653 smbXcli_conn_remote_name(cli->conn),
1654 netbios_domain_name, nt_errstr(status)));
1655 cli_shutdown(cli);
1656 TALLOC_FREE(frame);
1657 return status;
1658 }
1659
1660 cli_shutdown(cli);
1661 TALLOC_FREE(frame);
1662 return NT_STATUS_OK;
1663}
1664
1665/****************************************************************
1666****************************************************************/
1667
1668static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1669 struct libnet_JoinCtx *r)
1670{
1671 NTSTATUS status;
1672
1673 status = libnet_join_ok(r->in.msg_ctx,
1674 r->out.netbios_domain_name,
1675 r->in.dc_name,
1676 r->in.use_kerberos);
1677 if (!NT_STATUS_IS_OK(status)) {
1678 libnet_join_set_error_string(mem_ctx, r,
1679 "failed to verify domain membership after joining: %s",
1680 get_friendly_nt_error_msg(status));
1681 return WERR_SETUP_NOT_JOINED;
1682 }
1683
1684 return WERR_OK;
1685}
1686
1687/****************************************************************
1688****************************************************************/
1689
1690static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1691 struct libnet_UnjoinCtx *r)
1692{
1693 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1694 return false;
1695 }
1696
1697 if (!secrets_delete_domain_sid(lp_workgroup())) {
1698 return false;
1699 }
1700
1701 return true;
1702}
1703
1704/****************************************************************
1705****************************************************************/
1706
1707static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1708 struct libnet_UnjoinCtx *r)
1709{
1710 struct cli_state *cli = NULL;
1711 struct rpc_pipe_client *pipe_hnd = NULL;
1712 struct policy_handle sam_pol, domain_pol, user_pol;
1713 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1714 char *acct_name;
1715 uint32_t user_rid;
1716 struct lsa_String lsa_acct_name;
1717 struct samr_Ids user_rids;
1718 struct samr_Ids name_types;
1719 union samr_UserInfo *info = NULL;
1720 struct dcerpc_binding_handle *b = NULL;
1721
1722 ZERO_STRUCT(sam_pol);
1723 ZERO_STRUCT(domain_pol);
1724 ZERO_STRUCT(user_pol);
1725
1726 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1727 r->in.admin_account,
1728 r->in.admin_domain,
1729 r->in.admin_password,
1730 r->in.use_kerberos,
1731 &cli);
1732 if (!NT_STATUS_IS_OK(status)) {
1733 goto done;
1734 }
1735
1736 /* Open the domain */
1737
1738 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1739 &pipe_hnd);
1740 if (!NT_STATUS_IS_OK(status)) {
1741 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1742 nt_errstr(status)));
1743 goto done;
1744 }
1745
1746 b = pipe_hnd->binding_handle;
1747
1748 status = dcerpc_samr_Connect2(b, mem_ctx,
1749 pipe_hnd->desthost,
1750 SEC_FLAG_MAXIMUM_ALLOWED,
1751 &sam_pol,
1752 &result);
1753 if (!NT_STATUS_IS_OK(status)) {
1754 goto done;
1755 }
1756 if (!NT_STATUS_IS_OK(result)) {
1757 status = result;
1758 goto done;
1759 }
1760
1761 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1762 &sam_pol,
1763 SEC_FLAG_MAXIMUM_ALLOWED,
1764 r->in.domain_sid,
1765 &domain_pol,
1766 &result);
1767 if (!NT_STATUS_IS_OK(status)) {
1768 goto done;
1769 }
1770 if (!NT_STATUS_IS_OK(result)) {
1771 status = result;
1772 goto done;
1773 }
1774
1775 /* Create domain user */
1776
1777 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1778 if (!strlower_m(acct_name)) {
1779 status = NT_STATUS_INVALID_PARAMETER;
1780 goto done;
1781 }
1782
1783 init_lsa_String(&lsa_acct_name, acct_name);
1784
1785 status = dcerpc_samr_LookupNames(b, mem_ctx,
1786 &domain_pol,
1787 1,
1788 &lsa_acct_name,
1789 &user_rids,
1790 &name_types,
1791 &result);
1792
1793 if (!NT_STATUS_IS_OK(status)) {
1794 goto done;
1795 }
1796 if (!NT_STATUS_IS_OK(result)) {
1797 status = result;
1798 goto done;
1799 }
1800 if (user_rids.count != 1) {
1801 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1802 goto done;
1803 }
1804 if (name_types.count != 1) {
1805 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1806 goto done;
1807 }
1808
1809 if (name_types.ids[0] != SID_NAME_USER) {
1810 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1811 name_types.ids[0]));
1812 status = NT_STATUS_INVALID_WORKSTATION;
1813 goto done;
1814 }
1815
1816 user_rid = user_rids.ids[0];
1817
1818 /* Open handle on user */
1819
1820 status = dcerpc_samr_OpenUser(b, mem_ctx,
1821 &domain_pol,
1822 SEC_FLAG_MAXIMUM_ALLOWED,
1823 user_rid,
1824 &user_pol,
1825 &result);
1826 if (!NT_STATUS_IS_OK(status)) {
1827 goto done;
1828 }
1829 if (!NT_STATUS_IS_OK(result)) {
1830 status = result;
1831 goto done;
1832 }
1833
1834 /* Get user info */
1835
1836 status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1837 &user_pol,
1838 16,
1839 &info,
1840 &result);
1841 if (!NT_STATUS_IS_OK(status)) {
1842 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1843 goto done;
1844 }
1845 if (!NT_STATUS_IS_OK(result)) {
1846 status = result;
1847 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1848 goto done;
1849 }
1850
1851 /* now disable and setuser info */
1852
1853 info->info16.acct_flags |= ACB_DISABLED;
1854
1855 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1856 &user_pol,
1857 16,
1858 info,
1859 &result);
1860 if (!NT_STATUS_IS_OK(status)) {
1861 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1862 goto done;
1863 }
1864 if (!NT_STATUS_IS_OK(result)) {
1865 status = result;
1866 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1867 goto done;
1868 }
1869 status = result;
1870 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1871
1872done:
1873 if (pipe_hnd && b) {
1874 if (is_valid_policy_hnd(&domain_pol)) {
1875 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1876 }
1877 if (is_valid_policy_hnd(&sam_pol)) {
1878 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1879 }
1880 TALLOC_FREE(pipe_hnd);
1881 }
1882
1883 if (cli) {
1884 cli_shutdown(cli);
1885 }
1886
1887 return status;
1888}
1889
1890/****************************************************************
1891****************************************************************/
1892
1893static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1894{
1895 WERROR werr = WERR_OK;
1896 sbcErr err;
1897 struct smbconf_ctx *ctx;
1898
1899 err = smbconf_init_reg(r, &ctx, NULL);
1900 if (!SBC_ERROR_IS_OK(err)) {
1901 werr = WERR_NO_SUCH_SERVICE;
1902 goto done;
1903 }
1904
1905 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1906
1907 err = smbconf_set_global_parameter(ctx, "security", "user");
1908 if (!SBC_ERROR_IS_OK(err)) {
1909 werr = WERR_NO_SUCH_SERVICE;
1910 goto done;
1911 }
1912
1913 err = smbconf_set_global_parameter(ctx, "workgroup",
1914 r->in.domain_name);
1915 if (!SBC_ERROR_IS_OK(err)) {
1916 werr = WERR_NO_SUCH_SERVICE;
1917 goto done;
1918 }
1919
1920 smbconf_delete_global_parameter(ctx, "realm");
1921 goto done;
1922 }
1923
1924 err = smbconf_set_global_parameter(ctx, "security", "domain");
1925 if (!SBC_ERROR_IS_OK(err)) {
1926 werr = WERR_NO_SUCH_SERVICE;
1927 goto done;
1928 }
1929
1930 err = smbconf_set_global_parameter(ctx, "workgroup",
1931 r->out.netbios_domain_name);
1932 if (!SBC_ERROR_IS_OK(err)) {
1933 werr = WERR_NO_SUCH_SERVICE;
1934 goto done;
1935 }
1936
1937 if (r->out.domain_is_ad) {
1938 err = smbconf_set_global_parameter(ctx, "security", "ads");
1939 if (!SBC_ERROR_IS_OK(err)) {
1940 werr = WERR_NO_SUCH_SERVICE;
1941 goto done;
1942 }
1943
1944 err = smbconf_set_global_parameter(ctx, "realm",
1945 r->out.dns_domain_name);
1946 if (!SBC_ERROR_IS_OK(err)) {
1947 werr = WERR_NO_SUCH_SERVICE;
1948 goto done;
1949 }
1950 }
1951
1952 done:
1953 smbconf_shutdown(ctx);
1954 return werr;
1955}
1956
1957/****************************************************************
1958****************************************************************/
1959
1960static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1961{
1962 WERROR werr = WERR_OK;
1963 sbcErr err;
1964 struct smbconf_ctx *ctx;
1965
1966 err = smbconf_init_reg(r, &ctx, NULL);
1967 if (!SBC_ERROR_IS_OK(err)) {
1968 werr = WERR_NO_SUCH_SERVICE;
1969 goto done;
1970 }
1971
1972 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1973
1974 err = smbconf_set_global_parameter(ctx, "security", "user");
1975 if (!SBC_ERROR_IS_OK(err)) {
1976 werr = WERR_NO_SUCH_SERVICE;
1977 goto done;
1978 }
1979
1980 err = smbconf_delete_global_parameter(ctx, "workgroup");
1981 if (!SBC_ERROR_IS_OK(err)) {
1982 werr = WERR_NO_SUCH_SERVICE;
1983 goto done;
1984 }
1985
1986 smbconf_delete_global_parameter(ctx, "realm");
1987 }
1988
1989 done:
1990 smbconf_shutdown(ctx);
1991 return werr;
1992}
1993
1994/****************************************************************
1995****************************************************************/
1996
1997static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1998{
1999 WERROR werr;
2000
2001 if (!W_ERROR_IS_OK(r->out.result)) {
2002 return r->out.result;
2003 }
2004
2005 if (!r->in.modify_config) {
2006 return WERR_OK;
2007 }
2008
2009 werr = do_join_modify_vals_config(r);
2010 if (!W_ERROR_IS_OK(werr)) {
2011 return werr;
2012 }
2013
2014 lp_load_global(get_dyn_CONFIGFILE());
2015
2016 r->out.modified_config = true;
2017 r->out.result = werr;
2018
2019 return werr;
2020}
2021
2022/****************************************************************
2023****************************************************************/
2024
2025static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2026{
2027 WERROR werr;
2028
2029 if (!W_ERROR_IS_OK(r->out.result)) {
2030 return r->out.result;
2031 }
2032
2033 if (!r->in.modify_config) {
2034 return WERR_OK;
2035 }
2036
2037 werr = do_unjoin_modify_vals_config(r);
2038 if (!W_ERROR_IS_OK(werr)) {
2039 return werr;
2040 }
2041
2042 lp_load_global(get_dyn_CONFIGFILE());
2043
2044 r->out.modified_config = true;
2045 r->out.result = werr;
2046
2047 return werr;
2048}
2049
2050/****************************************************************
2051****************************************************************/
2052
2053static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
2054 const char *domain_str,
2055 const char **domain_p,
2056 const char **dc_p)
2057{
2058 char *domain = NULL;
2059 char *dc = NULL;
2060 const char *p = NULL;
2061
2062 if (!domain_str || !domain_p || !dc_p) {
2063 return false;
2064 }
2065
2066 p = strchr_m(domain_str, '\\');
2067
2068 if (p != NULL) {
2069 domain = talloc_strndup(mem_ctx, domain_str,
2070 PTR_DIFF(p, domain_str));
2071 dc = talloc_strdup(mem_ctx, p+1);
2072 if (!dc) {
2073 return false;
2074 }
2075 } else {
2076 domain = talloc_strdup(mem_ctx, domain_str);
2077 dc = NULL;
2078 }
2079 if (!domain) {
2080 return false;
2081 }
2082
2083 *domain_p = domain;
2084
2085 if (!*dc_p && dc) {
2086 *dc_p = dc;
2087 }
2088
2089 return true;
2090}
2091
2092/****************************************************************
2093****************************************************************/
2094
2095static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2096 struct libnet_JoinCtx *r)
2097{
2098 if (!r->in.domain_name) {
2099 libnet_join_set_error_string(mem_ctx, r,
2100 "No domain name defined");
2101 return WERR_INVALID_PARAM;
2102 }
2103
2104 if (strlen(r->in.machine_name) > 15) {
2105 libnet_join_set_error_string(mem_ctx, r,
2106 "Our netbios name can be at most 15 chars long, "
2107 "\"%s\" is %u chars long\n",
2108 r->in.machine_name,
2109 (unsigned int)strlen(r->in.machine_name));
2110 return WERR_INVALID_PARAM;
2111 }
2112
2113 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2114 &r->in.domain_name,
2115 &r->in.dc_name)) {
2116 libnet_join_set_error_string(mem_ctx, r,
2117 "Failed to parse domain name");
2118 return WERR_INVALID_PARAM;
2119 }
2120
2121 if (!r->in.admin_domain) {
2122 char *admin_domain = NULL;
2123 char *admin_account = NULL;
2124 split_domain_user(mem_ctx,
2125 r->in.admin_account,
2126 &admin_domain,
2127 &admin_account);
2128 r->in.admin_domain = admin_domain;
2129 r->in.admin_account = admin_account;
2130 }
2131
2132 if (!secrets_init()) {
2133 libnet_join_set_error_string(mem_ctx, r,
2134 "Unable to open secrets database");
2135 return WERR_CAN_NOT_COMPLETE;
2136 }
2137
2138 return WERR_OK;
2139}
2140
2141/****************************************************************
2142****************************************************************/
2143
2144static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2145{
2146 NTSTATUS status;
2147
2148 /* Try adding dom admins to builtin\admins. Only log failures. */
2149 status = create_builtin_administrators(domain_sid);
2150 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2151 DEBUG(10,("Unable to auto-add domain administrators to "
2152 "BUILTIN\\Administrators during join because "
2153 "winbindd must be running.\n"));
2154 } else if (!NT_STATUS_IS_OK(status)) {
2155 DEBUG(5, ("Failed to auto-add domain administrators to "
2156 "BUILTIN\\Administrators during join: %s\n",
2157 nt_errstr(status)));
2158 }
2159
2160 /* Try adding dom users to builtin\users. Only log failures. */
2161 status = create_builtin_users(domain_sid);
2162 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2163 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2164 "during join because winbindd must be running.\n"));
2165 } else if (!NT_STATUS_IS_OK(status)) {
2166 DEBUG(5, ("Failed to auto-add domain administrators to "
2167 "BUILTIN\\Administrators during join: %s\n",
2168 nt_errstr(status)));
2169 }
2170}
2171
2172/****************************************************************
2173****************************************************************/
2174
2175static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2176 struct libnet_JoinCtx *r)
2177{
2178 WERROR werr;
2179
2180 if (!W_ERROR_IS_OK(r->out.result)) {
2181 return r->out.result;
2182 }
2183
2184 werr = do_JoinConfig(r);
2185 if (!W_ERROR_IS_OK(werr)) {
2186 return werr;
2187 }
2188
2189 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2190 return WERR_OK;
2191 }
2192
2193 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2194 if (r->out.dns_domain_name) {
2195 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2196 }
2197
2198#ifdef HAVE_ADS
2199 if (r->out.domain_is_ad &&
2200 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2201 ADS_STATUS ads_status;
2202
2203 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
2204 if (!ADS_ERR_OK(ads_status)) {
2205 return WERR_GENERAL_FAILURE;
2206 }
2207 }
2208#endif /* HAVE_ADS */
2209
2210 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2211
2212 return WERR_OK;
2213}
2214
2215/****************************************************************
2216****************************************************************/
2217
2218static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2219{
2220 if (r->in.ads) {
2221 ads_destroy(&r->in.ads);
2222 }
2223
2224 return 0;
2225}
2226
2227/****************************************************************
2228****************************************************************/
2229
2230static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2231{
2232 if (r->in.ads) {
2233 ads_destroy(&r->in.ads);
2234 }
2235
2236 return 0;
2237}
2238
2239/****************************************************************
2240****************************************************************/
2241
2242WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2243 struct libnet_JoinCtx **r)
2244{
2245 struct libnet_JoinCtx *ctx;
2246
2247 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2248 if (!ctx) {
2249 return WERR_NOMEM;
2250 }
2251
2252 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2253
2254 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2255 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2256
2257 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2258
2259 ctx->in.desired_encryption_types = ENC_CRC32 |
2260 ENC_RSA_MD5 |
2261 ENC_RC4_HMAC_MD5;
2262#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
2263 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2264#endif
2265#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
2266 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2267#endif
2268
2269 *r = ctx;
2270
2271 return WERR_OK;
2272}
2273
2274/****************************************************************
2275****************************************************************/
2276
2277WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2278 struct libnet_UnjoinCtx **r)
2279{
2280 struct libnet_UnjoinCtx *ctx;
2281
2282 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2283 if (!ctx) {
2284 return WERR_NOMEM;
2285 }
2286
2287 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2288
2289 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2290 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2291
2292 *r = ctx;
2293
2294 return WERR_OK;
2295}
2296
2297/****************************************************************
2298****************************************************************/
2299
2300static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2301 struct libnet_JoinCtx *r)
2302{
2303 bool valid_security = false;
2304 bool valid_workgroup = false;
2305 bool valid_realm = false;
2306 bool ignored_realm = false;
2307
2308 /* check if configuration is already set correctly */
2309
2310 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2311
2312 switch (r->out.domain_is_ad) {
2313 case false:
2314 valid_security = (lp_security() == SEC_DOMAIN)
2315 || (lp_server_role() == ROLE_DOMAIN_PDC)
2316 || (lp_server_role() == ROLE_DOMAIN_BDC);
2317 if (valid_workgroup && valid_security) {
2318 /* nothing to be done */
2319 return WERR_OK;
2320 }
2321 break;
2322 case true:
2323 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2324 switch (lp_security()) {
2325 case SEC_DOMAIN:
2326 if (!valid_realm && lp_winbind_rpc_only()) {
2327 valid_realm = true;
2328 ignored_realm = true;
2329 }
2330 case SEC_ADS:
2331 valid_security = true;
2332 }
2333
2334 if (valid_workgroup && valid_realm && valid_security) {
2335 if (ignored_realm && !r->in.modify_config)
2336 {
2337 libnet_join_set_error_string(mem_ctx, r,
2338 "Warning: ignoring realm when "
2339 "joining AD domain with "
2340 "'security=domain' and "
2341 "'winbind rpc only = yes'. "
2342 "(realm set to '%s', "
2343 "should be '%s').", lp_realm(),
2344 r->out.dns_domain_name);
2345 }
2346 /* nothing to be done */
2347 return WERR_OK;
2348 }
2349 break;
2350 }
2351
2352 /* check if we are supposed to manipulate configuration */
2353
2354 if (!r->in.modify_config) {
2355
2356 char *wrong_conf = talloc_strdup(mem_ctx, "");
2357
2358 if (!valid_workgroup) {
2359 wrong_conf = talloc_asprintf_append(wrong_conf,
2360 "\"workgroup\" set to '%s', should be '%s'",
2361 lp_workgroup(), r->out.netbios_domain_name);
2362 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2363 }
2364
2365 if (!valid_realm) {
2366 wrong_conf = talloc_asprintf_append(wrong_conf,
2367 "\"realm\" set to '%s', should be '%s'",
2368 lp_realm(), r->out.dns_domain_name);
2369 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2370 }
2371
2372 if (!valid_security) {
2373 const char *sec = NULL;
2374 switch (lp_security()) {
2375 case SEC_USER: sec = "user"; break;
2376 case SEC_DOMAIN: sec = "domain"; break;
2377 case SEC_ADS: sec = "ads"; break;
2378 }
2379 wrong_conf = talloc_asprintf_append(wrong_conf,
2380 "\"security\" set to '%s', should be %s",
2381 sec, r->out.domain_is_ad ?
2382 "either 'domain' or 'ads'" : "'domain'");
2383 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2384 }
2385
2386 libnet_join_set_error_string(mem_ctx, r,
2387 "Invalid configuration (%s) and configuration modification "
2388 "was not requested", wrong_conf);
2389 return WERR_CAN_NOT_COMPLETE;
2390 }
2391
2392 /* check if we are able to manipulate configuration */
2393
2394 if (!lp_config_backend_is_registry()) {
2395 libnet_join_set_error_string(mem_ctx, r,
2396 "Configuration manipulation requested but not "
2397 "supported by backend");
2398 return WERR_NOT_SUPPORTED;
2399 }
2400
2401 return WERR_OK;
2402}
2403
2404/****************************************************************
2405****************************************************************/
2406
2407static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2408 struct libnet_JoinCtx *r)
2409{
2410 NTSTATUS status;
2411 WERROR werr;
2412 struct cli_state *cli = NULL;
2413#ifdef HAVE_ADS
2414 ADS_STATUS ads_status;
2415#endif /* HAVE_ADS */
2416 const char *pre_connect_realm = NULL;
2417 const char *numeric_dcip = NULL;
2418 const char *sitename = NULL;
2419
2420 /* Before contacting a DC, we can securely know
2421 * the realm only if the user specifies it.
2422 */
2423 if (r->in.use_kerberos &&
2424 r->in.domain_name_type == JoinDomNameTypeDNS) {
2425 pre_connect_realm = r->in.domain_name;
2426 }
2427
2428 if (!r->in.dc_name) {
2429 struct netr_DsRGetDCNameInfo *info;
2430 const char *dc;
2431 uint32_t name_type_flags = 0;
2432 if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2433 name_type_flags = DS_IS_DNS_NAME;
2434 } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2435 name_type_flags = DS_IS_FLAT_NAME;
2436 }
2437 status = dsgetdcname(mem_ctx,
2438 r->in.msg_ctx,
2439 r->in.domain_name,
2440 NULL,
2441 NULL,
2442 DS_FORCE_REDISCOVERY |
2443 DS_DIRECTORY_SERVICE_REQUIRED |
2444 DS_WRITABLE_REQUIRED |
2445 DS_RETURN_DNS_NAME |
2446 name_type_flags,
2447 &info);
2448 if (!NT_STATUS_IS_OK(status)) {
2449 libnet_join_set_error_string(mem_ctx, r,
2450 "failed to find DC for domain %s",
2451 r->in.domain_name,
2452 get_friendly_nt_error_msg(status));
2453 return WERR_DCNOTFOUND;
2454 }
2455
2456 dc = strip_hostname(info->dc_unc);
2457 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2458 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2459
2460 if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2461 info->dc_address[1] != '\\') {
2462 DBG_ERR("ill-formed DC address '%s'\n",
2463 info->dc_address);
2464 return WERR_DCNOTFOUND;
2465 }
2466
2467 numeric_dcip = info->dc_address + 2;
2468 sitename = info->dc_site_name;
2469 /* info goes out of scope but the memory stays
2470 allocated on the talloc context */
2471 }
2472
2473 if (pre_connect_realm != NULL) {
2474 struct sockaddr_storage ss = {0};
2475
2476 if (numeric_dcip != NULL) {
2477 if (!interpret_string_addr(&ss, numeric_dcip,
2478 AI_NUMERICHOST)) {
2479 DBG_ERR(
2480 "cannot parse IP address '%s' of DC '%s'\n",
2481 numeric_dcip, r->in.dc_name);
2482 return WERR_DCNOTFOUND;
2483 }
2484 } else {
2485 if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2486 DBG_WARNING(
2487 "cannot resolve IP address of DC '%s'\n",
2488 r->in.dc_name);
2489 return WERR_DCNOTFOUND;
2490 }
2491 }
2492
2493 /* The domain parameter is only used as modifier
2494 * to krb5.conf file name. .JOIN is is not a valid
2495 * NetBIOS name so it cannot clash with another domain
2496 * -- Uri.
2497 */
2498 create_local_private_krb5_conf_for_domain(
2499 pre_connect_realm, ".JOIN", sitename, &ss);
2500 }
2501
2502 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2503 if (!NT_STATUS_IS_OK(status)) {
2504 libnet_join_set_error_string(mem_ctx, r,
2505 "failed to lookup DC info for domain '%s' over rpc: %s",
2506 r->in.domain_name, get_friendly_nt_error_msg(status));
2507 return ntstatus_to_werror(status);
2508 }
2509
2510 werr = libnet_join_check_config(mem_ctx, r);
2511 if (!W_ERROR_IS_OK(werr)) {
2512 goto done;
2513 }
2514
2515#ifdef HAVE_ADS
2516
2517 create_local_private_krb5_conf_for_domain(
2518 r->out.dns_domain_name, r->out.netbios_domain_name,
2519 sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2520
2521 if (r->out.domain_is_ad &&
2522 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2523
2524 const char *initial_account_ou = r->in.account_ou;
2525
2526 /*
2527 * we want to create the msDS-SupportedEncryptionTypes attribute
2528 * as early as possible so always try an LDAP create as the user
2529 * first. We copy r->in.account_ou because it may be changed
2530 * during the machine pre-creation.
2531 */
2532
2533 ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2534 if (!ADS_ERR_OK(ads_status)) {
2535 return WERR_DEFAULT_JOIN_REQUIRED;
2536 }
2537
2538 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2539 if (ADS_ERR_OK(ads_status)) {
2540
2541 /*
2542 * LDAP object create succeeded, now go to the rpc
2543 * password set routines
2544 */
2545
2546 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2547 goto rpc_join;
2548 }
2549
2550 if (initial_account_ou != NULL) {
2551 libnet_join_set_error_string(mem_ctx, r,
2552 "failed to precreate account in ou %s: %s",
2553 r->in.account_ou,
2554 ads_errstr(ads_status));
2555 return WERR_DEFAULT_JOIN_REQUIRED;
2556 }
2557
2558 DEBUG(5, ("failed to precreate account in ou %s: %s",
2559 r->in.account_ou, ads_errstr(ads_status)));
2560 }
2561#endif /* HAVE_ADS */
2562
2563 rpc_join:
2564 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2565 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2566 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2567 } else {
2568 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2569 }
2570 if (!NT_STATUS_IS_OK(status)) {
2571 libnet_join_set_error_string(mem_ctx, r,
2572 "failed to join domain '%s' over rpc: %s",
2573 r->in.domain_name, get_friendly_nt_error_msg(status));
2574 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2575 return WERR_SETUP_ALREADY_JOINED;
2576 }
2577 werr = ntstatus_to_werror(status);
2578 goto done;
2579 }
2580
2581 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2582 werr = WERR_SETUP_NOT_JOINED;
2583 goto done;
2584 }
2585
2586 werr = WERR_OK;
2587
2588 done:
2589 if (cli) {
2590 cli_shutdown(cli);
2591 }
2592
2593 return werr;
2594}
2595
2596/****************************************************************
2597****************************************************************/
2598
2599static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2600 struct libnet_JoinCtx *r)
2601{
2602 WERROR werr;
2603 struct libnet_UnjoinCtx *u = NULL;
2604
2605 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2606 if (!W_ERROR_IS_OK(werr)) {
2607 return werr;
2608 }
2609
2610 u->in.debug = r->in.debug;
2611 u->in.dc_name = r->in.dc_name;
2612 u->in.domain_name = r->in.domain_name;
2613 u->in.admin_account = r->in.admin_account;
2614 u->in.admin_password = r->in.admin_password;
2615 u->in.modify_config = r->in.modify_config;
2616 u->in.use_kerberos = r->in.use_kerberos;
2617 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2618 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2619
2620 werr = libnet_Unjoin(mem_ctx, u);
2621 TALLOC_FREE(u);
2622
2623 return werr;
2624}
2625
2626/****************************************************************
2627****************************************************************/
2628
2629WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2630 struct libnet_JoinCtx *r)
2631{
2632 WERROR werr;
2633
2634 if (r->in.debug) {
2635 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2636 }
2637
2638 ZERO_STRUCT(r->out);
2639
2640 werr = libnet_join_pre_processing(mem_ctx, r);
2641 if (!W_ERROR_IS_OK(werr)) {
2642 goto done;
2643 }
2644
2645 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2646 werr = libnet_DomainJoin(mem_ctx, r);
2647 if (!W_ERROR_IS_OK(werr)) {
2648 goto done;
2649 }
2650 }
2651
2652 werr = libnet_join_post_processing(mem_ctx, r);
2653 if (!W_ERROR_IS_OK(werr)) {
2654 goto done;
2655 }
2656
2657 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2658 werr = libnet_join_post_verify(mem_ctx, r);
2659 if (!W_ERROR_IS_OK(werr)) {
2660 libnet_join_rollback(mem_ctx, r);
2661 }
2662 }
2663
2664 done:
2665 r->out.result = werr;
2666
2667 if (r->in.debug) {
2668 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2669 }
2670 return werr;
2671}
2672
2673/****************************************************************
2674****************************************************************/
2675
2676static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2677 struct libnet_UnjoinCtx *r)
2678{
2679 NTSTATUS status;
2680
2681 if (!r->in.domain_sid) {
2682 struct dom_sid sid;
2683 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2684 libnet_unjoin_set_error_string(mem_ctx, r,
2685 "Unable to fetch domain sid: are we joined?");
2686 return WERR_SETUP_NOT_JOINED;
2687 }
2688 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2689 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2690 }
2691
2692 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2693 !r->in.delete_machine_account) {
2694 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2695 return WERR_OK;
2696 }
2697
2698 if (!r->in.dc_name) {
2699 struct netr_DsRGetDCNameInfo *info;
2700 const char *dc;
2701 status = dsgetdcname(mem_ctx,
2702 r->in.msg_ctx,
2703 r->in.domain_name,
2704 NULL,
2705 NULL,
2706 DS_DIRECTORY_SERVICE_REQUIRED |
2707 DS_WRITABLE_REQUIRED |
2708 DS_RETURN_DNS_NAME,
2709 &info);
2710 if (!NT_STATUS_IS_OK(status)) {
2711 libnet_unjoin_set_error_string(mem_ctx, r,
2712 "failed to find DC for domain %s",
2713 r->in.domain_name,
2714 get_friendly_nt_error_msg(status));
2715 return WERR_DCNOTFOUND;
2716 }
2717
2718 dc = strip_hostname(info->dc_unc);
2719 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2720 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2721 }
2722
2723#ifdef HAVE_ADS
2724 /* for net ads leave, try to delete the account. If it works,
2725 no sense in disabling. If it fails, we can still try to
2726 disable it. jmcd */
2727
2728 if (r->in.delete_machine_account) {
2729 ADS_STATUS ads_status;
2730 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2731 if (ADS_ERR_OK(ads_status)) {
2732 /* dirty hack */
2733 r->out.dns_domain_name =
2734 talloc_strdup(mem_ctx,
2735 r->in.ads->server.realm);
2736 ads_status =
2737 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2738 }
2739 if (!ADS_ERR_OK(ads_status)) {
2740 libnet_unjoin_set_error_string(mem_ctx, r,
2741 "failed to remove machine account from AD: %s",
2742 ads_errstr(ads_status));
2743 } else {
2744 r->out.deleted_machine_account = true;
2745 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2746 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2747 return WERR_OK;
2748 }
2749 }
2750#endif /* HAVE_ADS */
2751
2752 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2753 "disable". */
2754 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2755 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2756 if (!NT_STATUS_IS_OK(status)) {
2757 libnet_unjoin_set_error_string(mem_ctx, r,
2758 "failed to disable machine account via rpc: %s",
2759 get_friendly_nt_error_msg(status));
2760 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2761 return WERR_SETUP_NOT_JOINED;
2762 }
2763 return ntstatus_to_werror(status);
2764 }
2765
2766 r->out.disabled_machine_account = true;
2767 }
2768
2769 /* If disable succeeded or was not requested at all, we
2770 should be getting rid of our end of things */
2771
2772 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2773
2774 return WERR_OK;
2775}
2776
2777/****************************************************************
2778****************************************************************/
2779
2780static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2781 struct libnet_UnjoinCtx *r)
2782{
2783 if (!r->in.domain_name) {
2784 libnet_unjoin_set_error_string(mem_ctx, r,
2785 "No domain name defined");
2786 return WERR_INVALID_PARAM;
2787 }
2788
2789 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2790 &r->in.domain_name,
2791 &r->in.dc_name)) {
2792 libnet_unjoin_set_error_string(mem_ctx, r,
2793 "Failed to parse domain name");
2794 return WERR_INVALID_PARAM;
2795 }
2796
2797 if (IS_DC) {
2798 return WERR_SETUP_DOMAIN_CONTROLLER;
2799 }
2800
2801 if (!r->in.admin_domain) {
2802 char *admin_domain = NULL;
2803 char *admin_account = NULL;
2804 split_domain_user(mem_ctx,
2805 r->in.admin_account,
2806 &admin_domain,
2807 &admin_account);
2808 r->in.admin_domain = admin_domain;
2809 r->in.admin_account = admin_account;
2810 }
2811
2812 if (!secrets_init()) {
2813 libnet_unjoin_set_error_string(mem_ctx, r,
2814 "Unable to open secrets database");
2815 return WERR_CAN_NOT_COMPLETE;
2816 }
2817
2818 return WERR_OK;
2819}
2820
2821/****************************************************************
2822****************************************************************/
2823
2824static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2825 struct libnet_UnjoinCtx *r)
2826{
2827 saf_delete(r->out.netbios_domain_name);
2828 saf_delete(r->out.dns_domain_name);
2829
2830 return libnet_unjoin_config(r);
2831}
2832
2833/****************************************************************
2834****************************************************************/
2835
2836WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2837 struct libnet_UnjoinCtx *r)
2838{
2839 WERROR werr;
2840
2841 if (r->in.debug) {
2842 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2843 }
2844
2845 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2846 if (!W_ERROR_IS_OK(werr)) {
2847 goto done;
2848 }
2849
2850 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2851 werr = libnet_DomainUnjoin(mem_ctx, r);
2852 if (!W_ERROR_IS_OK(werr)) {
2853 libnet_unjoin_config(r);
2854 goto done;
2855 }
2856 }
2857
2858 werr = libnet_unjoin_post_processing(mem_ctx, r);
2859 if (!W_ERROR_IS_OK(werr)) {
2860 goto done;
2861 }
2862
2863 done:
2864 r->out.result = werr;
2865
2866 if (r->in.debug) {
2867 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2868 }
2869
2870 return werr;
2871}
Note: See TracBrowser for help on using the repository browser.