s3:torture:delete: untangle function call from result check
[Samba/gebeck_regimport.git] / source3 / libnet / libnet_join.c
blob399c13a86a72693227ac2093bba1e8f788c80a2f
1 /*
2 * Unix SMB/CIFS implementation.
3 * libnet Join Support
4 * Copyright (C) Gerald (Jerry) Carter 2006
5 * Copyright (C) Guenther Deschner 2007-2008
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "ads.h"
23 #include "librpc/gen_ndr/ndr_libnet_join.h"
24 #include "libnet/libnet_join.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../librpc/gen_ndr/ndr_samr_c.h"
27 #include "rpc_client/init_samr.h"
28 #include "../librpc/gen_ndr/ndr_lsa_c.h"
29 #include "rpc_client/cli_lsarpc.h"
30 #include "../librpc/gen_ndr/ndr_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
32 #include "lib/smbconf/smbconf.h"
33 #include "lib/smbconf/smbconf_reg.h"
34 #include "../libds/common/flags.h"
35 #include "secrets.h"
36 #include "rpc_client/init_lsa.h"
37 #include "rpc_client/cli_pipe.h"
38 #include "../libcli/security/security.h"
39 #include "passdb.h"
40 #include "libsmb/libsmb.h"
41 #include "../libcli/smb/smbXcli_base.h"
42 #include "lib/param/loadparm.h"
44 /****************************************************************
45 ****************************************************************/
47 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
48 do { \
49 char *str = NULL; \
50 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
51 DEBUG(1,("libnet_Join:\n%s", str)); \
52 TALLOC_FREE(str); \
53 } while (0)
55 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
56 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
57 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
58 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
60 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
61 do { \
62 char *str = NULL; \
63 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
64 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
65 TALLOC_FREE(str); \
66 } while (0)
68 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
69 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
70 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
71 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
73 /****************************************************************
74 ****************************************************************/
76 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
77 struct libnet_JoinCtx *r,
78 const char *format, ...)
80 va_list args;
82 if (r->out.error_string) {
83 return;
86 va_start(args, format);
87 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
88 va_end(args);
91 /****************************************************************
92 ****************************************************************/
94 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
95 struct libnet_UnjoinCtx *r,
96 const char *format, ...)
98 va_list args;
100 if (r->out.error_string) {
101 return;
104 va_start(args, format);
105 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
106 va_end(args);
109 #ifdef HAVE_ADS
111 /****************************************************************
112 ****************************************************************/
114 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
115 const char *netbios_domain_name,
116 const char *dc_name,
117 const char *user_name,
118 const char *password,
119 ADS_STRUCT **ads)
121 ADS_STATUS status;
122 ADS_STRUCT *my_ads = NULL;
123 char *cp;
125 my_ads = ads_init(dns_domain_name,
126 netbios_domain_name,
127 dc_name);
128 if (!my_ads) {
129 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
132 if (user_name) {
133 SAFE_FREE(my_ads->auth.user_name);
134 my_ads->auth.user_name = SMB_STRDUP(user_name);
135 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
136 *cp++ = '\0';
137 SAFE_FREE(my_ads->auth.realm);
138 my_ads->auth.realm = smb_xstrdup(cp);
139 strupper_m(my_ads->auth.realm);
143 if (password) {
144 SAFE_FREE(my_ads->auth.password);
145 my_ads->auth.password = SMB_STRDUP(password);
148 status = ads_connect_user_creds(my_ads);
149 if (!ADS_ERR_OK(status)) {
150 ads_destroy(&my_ads);
151 return status;
154 *ads = my_ads;
155 return ADS_SUCCESS;
158 /****************************************************************
159 ****************************************************************/
161 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
162 struct libnet_JoinCtx *r)
164 ADS_STATUS status;
166 status = libnet_connect_ads(r->out.dns_domain_name,
167 r->out.netbios_domain_name,
168 r->in.dc_name,
169 r->in.admin_account,
170 r->in.admin_password,
171 &r->in.ads);
172 if (!ADS_ERR_OK(status)) {
173 libnet_join_set_error_string(mem_ctx, r,
174 "failed to connect to AD: %s",
175 ads_errstr(status));
176 return status;
179 if (!r->out.netbios_domain_name) {
180 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
181 r->in.ads->server.workgroup);
182 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
185 if (!r->out.dns_domain_name) {
186 r->out.dns_domain_name = talloc_strdup(mem_ctx,
187 r->in.ads->config.realm);
188 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
191 r->out.domain_is_ad = true;
193 return ADS_SUCCESS;
196 /****************************************************************
197 ****************************************************************/
199 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
200 struct libnet_UnjoinCtx *r)
202 ADS_STATUS status;
204 status = libnet_connect_ads(r->in.domain_name,
205 r->in.domain_name,
206 r->in.dc_name,
207 r->in.admin_account,
208 r->in.admin_password,
209 &r->in.ads);
210 if (!ADS_ERR_OK(status)) {
211 libnet_unjoin_set_error_string(mem_ctx, r,
212 "failed to connect to AD: %s",
213 ads_errstr(status));
216 return status;
219 /****************************************************************
220 join a domain using ADS (LDAP mods)
221 ****************************************************************/
223 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
224 struct libnet_JoinCtx *r)
226 ADS_STATUS status;
227 LDAPMessage *res = NULL;
228 const char *attrs[] = { "dn", NULL };
229 bool moved = false;
231 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
232 if (!ADS_ERR_OK(status)) {
233 return status;
236 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
237 if (!ADS_ERR_OK(status)) {
238 return status;
241 if (ads_count_replies(r->in.ads, res) != 1) {
242 ads_msgfree(r->in.ads, res);
243 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
246 ads_msgfree(r->in.ads, res);
248 /* Attempt to create the machine account and bail if this fails.
249 Assume that the admin wants exactly what they requested */
251 status = ads_create_machine_acct(r->in.ads,
252 r->in.machine_name,
253 r->in.account_ou);
255 if (ADS_ERR_OK(status)) {
256 DEBUG(1,("machine account creation created\n"));
257 return status;
258 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
259 (status.err.rc == LDAP_ALREADY_EXISTS)) {
260 status = ADS_SUCCESS;
263 if (!ADS_ERR_OK(status)) {
264 DEBUG(1,("machine account creation failed\n"));
265 return status;
268 status = ads_move_machine_acct(r->in.ads,
269 r->in.machine_name,
270 r->in.account_ou,
271 &moved);
272 if (!ADS_ERR_OK(status)) {
273 DEBUG(1,("failure to locate/move pre-existing "
274 "machine account\n"));
275 return status;
278 DEBUG(1,("The machine account %s the specified OU.\n",
279 moved ? "was moved into" : "already exists in"));
281 return status;
284 /****************************************************************
285 ****************************************************************/
287 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
288 struct libnet_UnjoinCtx *r)
290 ADS_STATUS status;
292 if (!r->in.ads) {
293 status = libnet_unjoin_connect_ads(mem_ctx, r);
294 if (!ADS_ERR_OK(status)) {
295 libnet_unjoin_set_error_string(mem_ctx, r,
296 "failed to connect to AD: %s",
297 ads_errstr(status));
298 return status;
302 status = ads_leave_realm(r->in.ads, r->in.machine_name);
303 if (!ADS_ERR_OK(status)) {
304 libnet_unjoin_set_error_string(mem_ctx, r,
305 "failed to leave realm: %s",
306 ads_errstr(status));
307 return status;
310 return ADS_SUCCESS;
313 /****************************************************************
314 ****************************************************************/
316 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
317 struct libnet_JoinCtx *r)
319 ADS_STATUS status;
320 LDAPMessage *res = NULL;
321 char *dn = NULL;
323 if (!r->in.machine_name) {
324 return ADS_ERROR(LDAP_NO_MEMORY);
327 status = ads_find_machine_acct(r->in.ads,
328 &res,
329 r->in.machine_name);
330 if (!ADS_ERR_OK(status)) {
331 return status;
334 if (ads_count_replies(r->in.ads, res) != 1) {
335 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
336 goto done;
339 dn = ads_get_dn(r->in.ads, mem_ctx, res);
340 if (!dn) {
341 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
342 goto done;
345 r->out.dn = talloc_strdup(mem_ctx, dn);
346 if (!r->out.dn) {
347 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
348 goto done;
351 done:
352 ads_msgfree(r->in.ads, res);
353 TALLOC_FREE(dn);
355 return status;
358 /****************************************************************
359 Set a machines dNSHostName and servicePrincipalName attributes
360 ****************************************************************/
362 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
363 struct libnet_JoinCtx *r)
365 ADS_STATUS status;
366 ADS_MODLIST mods;
367 fstring my_fqdn;
368 const char *spn_array[3] = {NULL, NULL, NULL};
369 char *spn = NULL;
371 /* Find our DN */
373 status = libnet_join_find_machine_acct(mem_ctx, r);
374 if (!ADS_ERR_OK(status)) {
375 return status;
378 /* Windows only creates HOST/shortname & HOST/fqdn. */
380 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
381 if (!spn) {
382 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
384 strupper_m(spn);
385 spn_array[0] = spn;
387 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
388 || (strchr(my_fqdn, '.') == NULL)) {
389 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
390 r->out.dns_domain_name);
393 strlower_m(my_fqdn);
395 if (!strequal(my_fqdn, r->in.machine_name)) {
396 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
397 if (!spn) {
398 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
400 spn_array[1] = spn;
403 mods = ads_init_mods(mem_ctx);
404 if (!mods) {
405 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
408 /* fields of primary importance */
410 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
411 if (!ADS_ERR_OK(status)) {
412 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
415 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
416 spn_array);
417 if (!ADS_ERR_OK(status)) {
418 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
421 return ads_gen_mod(r->in.ads, r->out.dn, mods);
424 /****************************************************************
425 ****************************************************************/
427 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
428 struct libnet_JoinCtx *r)
430 ADS_STATUS status;
431 ADS_MODLIST mods;
433 if (!r->in.create_upn) {
434 return ADS_SUCCESS;
437 /* Find our DN */
439 status = libnet_join_find_machine_acct(mem_ctx, r);
440 if (!ADS_ERR_OK(status)) {
441 return status;
444 if (!r->in.upn) {
445 r->in.upn = talloc_asprintf(mem_ctx,
446 "host/%s@%s",
447 r->in.machine_name,
448 r->out.dns_domain_name);
449 if (!r->in.upn) {
450 return ADS_ERROR(LDAP_NO_MEMORY);
454 /* now do the mods */
456 mods = ads_init_mods(mem_ctx);
457 if (!mods) {
458 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
461 /* fields of primary importance */
463 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
464 if (!ADS_ERR_OK(status)) {
465 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
468 return ads_gen_mod(r->in.ads, r->out.dn, mods);
472 /****************************************************************
473 ****************************************************************/
475 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
476 struct libnet_JoinCtx *r)
478 ADS_STATUS status;
479 ADS_MODLIST mods;
480 char *os_sp = NULL;
482 if (!r->in.os_name || !r->in.os_version ) {
483 return ADS_SUCCESS;
486 /* Find our DN */
488 status = libnet_join_find_machine_acct(mem_ctx, r);
489 if (!ADS_ERR_OK(status)) {
490 return status;
493 /* now do the mods */
495 mods = ads_init_mods(mem_ctx);
496 if (!mods) {
497 return ADS_ERROR(LDAP_NO_MEMORY);
500 os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
501 if (!os_sp) {
502 return ADS_ERROR(LDAP_NO_MEMORY);
505 /* fields of primary importance */
507 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
508 r->in.os_name);
509 if (!ADS_ERR_OK(status)) {
510 return status;
513 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
514 r->in.os_version);
515 if (!ADS_ERR_OK(status)) {
516 return status;
519 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
520 os_sp);
521 if (!ADS_ERR_OK(status)) {
522 return status;
525 return ads_gen_mod(r->in.ads, r->out.dn, mods);
528 /****************************************************************
529 ****************************************************************/
531 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
532 struct libnet_JoinCtx *r)
534 if (!USE_SYSTEM_KEYTAB) {
535 return true;
538 if (ads_keytab_create_default(r->in.ads) != 0) {
539 return false;
542 return true;
545 /****************************************************************
546 ****************************************************************/
548 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
549 struct libnet_JoinCtx *r)
551 uint32_t domain_func;
552 ADS_STATUS status;
553 const char *salt = NULL;
554 char *std_salt = NULL;
556 status = ads_domain_func_level(r->in.ads, &domain_func);
557 if (!ADS_ERR_OK(status)) {
558 libnet_join_set_error_string(mem_ctx, r,
559 "failed to determine domain functional level: %s",
560 ads_errstr(status));
561 return false;
564 /* go ahead and setup the default salt */
566 std_salt = kerberos_standard_des_salt();
567 if (!std_salt) {
568 libnet_join_set_error_string(mem_ctx, r,
569 "failed to obtain standard DES salt");
570 return false;
573 salt = talloc_strdup(mem_ctx, std_salt);
574 if (!salt) {
575 return false;
578 SAFE_FREE(std_salt);
580 /* if it's a Windows functional domain, we have to look for the UPN */
582 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
583 char *upn;
585 upn = ads_get_upn(r->in.ads, mem_ctx,
586 r->in.machine_name);
587 if (upn) {
588 salt = talloc_strdup(mem_ctx, upn);
589 if (!salt) {
590 return false;
595 return kerberos_secrets_store_des_salt(salt);
598 /****************************************************************
599 ****************************************************************/
601 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
602 struct libnet_JoinCtx *r)
604 ADS_STATUS status;
606 if (!r->in.ads) {
607 status = libnet_join_connect_ads(mem_ctx, r);
608 if (!ADS_ERR_OK(status)) {
609 return status;
613 status = libnet_join_set_machine_spn(mem_ctx, r);
614 if (!ADS_ERR_OK(status)) {
615 libnet_join_set_error_string(mem_ctx, r,
616 "failed to set machine spn: %s",
617 ads_errstr(status));
618 return status;
621 status = libnet_join_set_os_attributes(mem_ctx, r);
622 if (!ADS_ERR_OK(status)) {
623 libnet_join_set_error_string(mem_ctx, r,
624 "failed to set machine os attributes: %s",
625 ads_errstr(status));
626 return status;
629 status = libnet_join_set_machine_upn(mem_ctx, r);
630 if (!ADS_ERR_OK(status)) {
631 libnet_join_set_error_string(mem_ctx, r,
632 "failed to set machine upn: %s",
633 ads_errstr(status));
634 return status;
637 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
638 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
641 if (!libnet_join_create_keytab(mem_ctx, r)) {
642 libnet_join_set_error_string(mem_ctx, r,
643 "failed to create kerberos keytab");
644 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
647 return ADS_SUCCESS;
649 #endif /* HAVE_ADS */
651 /****************************************************************
652 Store the machine password and domain SID
653 ****************************************************************/
655 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
656 struct libnet_JoinCtx *r)
658 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
659 r->out.domain_sid))
661 DEBUG(1,("Failed to save domain sid\n"));
662 return false;
665 if (!secrets_store_machine_password(r->in.machine_password,
666 r->out.netbios_domain_name,
667 r->in.secure_channel_type))
669 DEBUG(1,("Failed to save machine password\n"));
670 return false;
673 return true;
676 /****************************************************************
677 Connect dc's IPC$ share
678 ****************************************************************/
680 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
681 const char *user,
682 const char *pass,
683 bool use_kerberos,
684 struct cli_state **cli)
686 int flags = 0;
688 if (use_kerberos) {
689 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
692 if (use_kerberos && pass) {
693 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
696 return cli_full_connection(cli, NULL,
698 NULL, 0,
699 "IPC$", "IPC",
700 user,
701 NULL,
702 pass,
703 flags,
704 SMB_SIGNING_DEFAULT);
707 /****************************************************************
708 Lookup domain dc's info
709 ****************************************************************/
711 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
712 struct libnet_JoinCtx *r,
713 struct cli_state **cli)
715 struct rpc_pipe_client *pipe_hnd = NULL;
716 struct policy_handle lsa_pol;
717 NTSTATUS status, result;
718 union lsa_PolicyInformation *info = NULL;
719 struct dcerpc_binding_handle *b;
721 status = libnet_join_connect_dc_ipc(r->in.dc_name,
722 r->in.admin_account,
723 r->in.admin_password,
724 r->in.use_kerberos,
725 cli);
726 if (!NT_STATUS_IS_OK(status)) {
727 goto done;
730 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
731 &pipe_hnd);
732 if (!NT_STATUS_IS_OK(status)) {
733 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
734 nt_errstr(status)));
735 goto done;
738 b = pipe_hnd->binding_handle;
740 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
741 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
742 if (!NT_STATUS_IS_OK(status)) {
743 goto done;
746 status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
747 &lsa_pol,
748 LSA_POLICY_INFO_DNS,
749 &info,
750 &result);
751 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
752 r->out.domain_is_ad = true;
753 r->out.netbios_domain_name = info->dns.name.string;
754 r->out.dns_domain_name = info->dns.dns_domain.string;
755 r->out.forest_name = info->dns.dns_forest.string;
756 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
757 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
760 if (!NT_STATUS_IS_OK(status)) {
761 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
762 &lsa_pol,
763 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
764 &info,
765 &result);
766 if (!NT_STATUS_IS_OK(status)) {
767 goto done;
769 if (!NT_STATUS_IS_OK(result)) {
770 status = result;
771 goto done;
774 r->out.netbios_domain_name = info->account_domain.name.string;
775 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
776 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
779 dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
780 TALLOC_FREE(pipe_hnd);
782 done:
783 return status;
786 /****************************************************************
787 Do the domain join unsecure
788 ****************************************************************/
790 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
791 struct libnet_JoinCtx *r,
792 struct cli_state *cli)
794 struct rpc_pipe_client *pipe_hnd = NULL;
795 unsigned char orig_trust_passwd_hash[16];
796 unsigned char new_trust_passwd_hash[16];
797 fstring trust_passwd;
798 NTSTATUS status;
800 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
801 &pipe_hnd);
802 if (!NT_STATUS_IS_OK(status)) {
803 return status;
806 if (!r->in.machine_password) {
807 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
808 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
811 E_md4hash(r->in.machine_password, new_trust_passwd_hash);
813 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
814 fstrcpy(trust_passwd, r->in.admin_password);
815 strlower_m(trust_passwd);
818 * Machine names can be 15 characters, but the max length on
819 * a password is 14. --jerry
822 trust_passwd[14] = '\0';
824 E_md4hash(trust_passwd, orig_trust_passwd_hash);
826 status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx,
827 r->in.machine_name,
828 orig_trust_passwd_hash,
829 r->in.machine_password,
830 new_trust_passwd_hash,
831 r->in.secure_channel_type);
833 return status;
836 /****************************************************************
837 Do the domain join
838 ****************************************************************/
840 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
841 struct libnet_JoinCtx *r,
842 struct cli_state *cli)
844 struct rpc_pipe_client *pipe_hnd = NULL;
845 struct policy_handle sam_pol, domain_pol, user_pol;
846 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
847 char *acct_name;
848 struct lsa_String lsa_acct_name;
849 uint32_t user_rid;
850 uint32_t acct_flags = ACB_WSTRUST;
851 struct samr_Ids user_rids;
852 struct samr_Ids name_types;
853 union samr_UserInfo user_info;
854 struct dcerpc_binding_handle *b = NULL;
856 DATA_BLOB session_key = data_blob_null;
857 struct samr_CryptPassword crypt_pwd;
858 struct samr_CryptPasswordEx crypt_pwd_ex;
860 ZERO_STRUCT(sam_pol);
861 ZERO_STRUCT(domain_pol);
862 ZERO_STRUCT(user_pol);
864 switch (r->in.secure_channel_type) {
865 case SEC_CHAN_WKSTA:
866 acct_flags = ACB_WSTRUST;
867 break;
868 case SEC_CHAN_BDC:
869 acct_flags = ACB_SVRTRUST;
870 break;
871 default:
872 return NT_STATUS_INVALID_PARAMETER;
875 if (!r->in.machine_password) {
876 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
877 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
880 /* Open the domain */
882 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
883 &pipe_hnd);
884 if (!NT_STATUS_IS_OK(status)) {
885 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
886 nt_errstr(status)));
887 goto done;
890 b = pipe_hnd->binding_handle;
892 status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
893 if (!NT_STATUS_IS_OK(status)) {
894 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
895 nt_errstr(status)));
896 goto done;
899 status = dcerpc_samr_Connect2(b, mem_ctx,
900 pipe_hnd->desthost,
901 SAMR_ACCESS_ENUM_DOMAINS
902 | SAMR_ACCESS_LOOKUP_DOMAIN,
903 &sam_pol,
904 &result);
905 if (!NT_STATUS_IS_OK(status)) {
906 goto done;
908 if (!NT_STATUS_IS_OK(result)) {
909 status = result;
910 goto done;
913 status = dcerpc_samr_OpenDomain(b, mem_ctx,
914 &sam_pol,
915 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
916 | SAMR_DOMAIN_ACCESS_CREATE_USER
917 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
918 r->out.domain_sid,
919 &domain_pol,
920 &result);
921 if (!NT_STATUS_IS_OK(status)) {
922 goto done;
924 if (!NT_STATUS_IS_OK(result)) {
925 status = result;
926 goto done;
929 /* Create domain user */
931 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
932 strlower_m(acct_name);
934 init_lsa_String(&lsa_acct_name, acct_name);
936 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
937 uint32_t access_desired =
938 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
939 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
940 SAMR_USER_ACCESS_SET_PASSWORD |
941 SAMR_USER_ACCESS_GET_ATTRIBUTES |
942 SAMR_USER_ACCESS_SET_ATTRIBUTES;
943 uint32_t access_granted = 0;
945 DEBUG(10,("Creating account with desired access mask: %d\n",
946 access_desired));
948 status = dcerpc_samr_CreateUser2(b, mem_ctx,
949 &domain_pol,
950 &lsa_acct_name,
951 acct_flags,
952 access_desired,
953 &user_pol,
954 &access_granted,
955 &user_rid,
956 &result);
957 if (!NT_STATUS_IS_OK(status)) {
958 goto done;
961 status = result;
962 if (!NT_STATUS_IS_OK(status) &&
963 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
965 DEBUG(10,("Creation of workstation account failed: %s\n",
966 nt_errstr(status)));
968 /* If NT_STATUS_ACCESS_DENIED then we have a valid
969 username/password combo but the user does not have
970 administrator access. */
972 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
973 libnet_join_set_error_string(mem_ctx, r,
974 "User specified does not have "
975 "administrator privileges");
978 goto done;
981 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
982 if (!(r->in.join_flags &
983 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
984 goto done;
988 /* We *must* do this.... don't ask... */
990 if (NT_STATUS_IS_OK(status)) {
991 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
995 status = dcerpc_samr_LookupNames(b, mem_ctx,
996 &domain_pol,
998 &lsa_acct_name,
999 &user_rids,
1000 &name_types,
1001 &result);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 goto done;
1005 if (!NT_STATUS_IS_OK(result)) {
1006 status = result;
1007 goto done;
1010 if (name_types.ids[0] != SID_NAME_USER) {
1011 DEBUG(0,("%s is not a user account (type=%d)\n",
1012 acct_name, name_types.ids[0]));
1013 status = NT_STATUS_INVALID_WORKSTATION;
1014 goto done;
1017 user_rid = user_rids.ids[0];
1019 /* Open handle on user */
1021 status = dcerpc_samr_OpenUser(b, mem_ctx,
1022 &domain_pol,
1023 SEC_FLAG_MAXIMUM_ALLOWED,
1024 user_rid,
1025 &user_pol,
1026 &result);
1027 if (!NT_STATUS_IS_OK(status)) {
1028 goto done;
1030 if (!NT_STATUS_IS_OK(result)) {
1031 status = result;
1032 goto done;
1035 /* Fill in the additional account flags now */
1037 acct_flags |= ACB_PWNOEXP;
1039 /* Set account flags on machine account */
1040 ZERO_STRUCT(user_info.info16);
1041 user_info.info16.acct_flags = acct_flags;
1043 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1044 &user_pol,
1046 &user_info,
1047 &result);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 dcerpc_samr_DeleteUser(b, mem_ctx,
1050 &user_pol,
1051 &result);
1053 libnet_join_set_error_string(mem_ctx, r,
1054 "Failed to set account flags for machine account (%s)\n",
1055 nt_errstr(status));
1056 goto done;
1059 if (!NT_STATUS_IS_OK(result)) {
1060 status = result;
1062 dcerpc_samr_DeleteUser(b, mem_ctx,
1063 &user_pol,
1064 &result);
1066 libnet_join_set_error_string(mem_ctx, r,
1067 "Failed to set account flags for machine account (%s)\n",
1068 nt_errstr(status));
1069 goto done;
1072 /* Set password on machine account - first try level 26 */
1074 init_samr_CryptPasswordEx(r->in.machine_password,
1075 &session_key,
1076 &crypt_pwd_ex);
1078 user_info.info26.password = crypt_pwd_ex;
1079 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1081 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1082 &user_pol,
1084 &user_info,
1085 &result);
1087 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1089 /* retry with level 24 */
1091 init_samr_CryptPassword(r->in.machine_password,
1092 &session_key,
1093 &crypt_pwd);
1095 user_info.info24.password = crypt_pwd;
1096 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1098 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1099 &user_pol,
1101 &user_info,
1102 &result);
1105 if (!NT_STATUS_IS_OK(status)) {
1107 dcerpc_samr_DeleteUser(b, mem_ctx,
1108 &user_pol,
1109 &result);
1111 libnet_join_set_error_string(mem_ctx, r,
1112 "Failed to set password for machine account (%s)\n",
1113 nt_errstr(status));
1114 goto done;
1116 if (!NT_STATUS_IS_OK(result)) {
1117 status = result;
1119 dcerpc_samr_DeleteUser(b, mem_ctx,
1120 &user_pol,
1121 &result);
1123 libnet_join_set_error_string(mem_ctx, r,
1124 "Failed to set password for machine account (%s)\n",
1125 nt_errstr(status));
1126 goto done;
1129 status = NT_STATUS_OK;
1131 done:
1132 if (!pipe_hnd) {
1133 return status;
1136 data_blob_clear_free(&session_key);
1138 if (is_valid_policy_hnd(&sam_pol)) {
1139 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1141 if (is_valid_policy_hnd(&domain_pol)) {
1142 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1144 if (is_valid_policy_hnd(&user_pol)) {
1145 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1147 TALLOC_FREE(pipe_hnd);
1149 return status;
1152 /****************************************************************
1153 ****************************************************************/
1155 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
1156 const char *machine_name,
1157 const char *dc_name)
1159 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
1160 struct cli_state *cli = NULL;
1161 struct rpc_pipe_client *pipe_hnd = NULL;
1162 struct rpc_pipe_client *netlogon_pipe = NULL;
1163 NTSTATUS status;
1164 char *machine_password = NULL;
1165 char *machine_account = NULL;
1167 if (!dc_name) {
1168 return NT_STATUS_INVALID_PARAMETER;
1171 if (!secrets_init()) {
1172 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1175 machine_password = secrets_fetch_machine_password(netbios_domain_name,
1176 NULL, NULL);
1177 if (!machine_password) {
1178 return NT_STATUS_NO_TRUST_LSA_SECRET;
1181 if (asprintf(&machine_account, "%s$", machine_name) == -1) {
1182 SAFE_FREE(machine_password);
1183 return NT_STATUS_NO_MEMORY;
1186 status = cli_full_connection(&cli, NULL,
1187 dc_name,
1188 NULL, 0,
1189 "IPC$", "IPC",
1190 machine_account,
1191 NULL,
1192 machine_password,
1194 SMB_SIGNING_DEFAULT);
1195 free(machine_account);
1196 free(machine_password);
1198 if (!NT_STATUS_IS_OK(status)) {
1199 status = cli_full_connection(&cli, NULL,
1200 dc_name,
1201 NULL, 0,
1202 "IPC$", "IPC",
1204 NULL,
1207 SMB_SIGNING_DEFAULT);
1210 if (!NT_STATUS_IS_OK(status)) {
1211 return status;
1214 status = get_schannel_session_key(cli, netbios_domain_name,
1215 &neg_flags, &netlogon_pipe);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
1218 cli_shutdown(cli);
1219 return NT_STATUS_OK;
1222 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1223 "key from server %s for domain %s. Error was %s\n",
1224 smbXcli_conn_remote_name(cli->conn),
1225 netbios_domain_name, nt_errstr(status)));
1226 cli_shutdown(cli);
1227 return status;
1230 if (!lp_client_schannel()) {
1231 cli_shutdown(cli);
1232 return NT_STATUS_OK;
1235 status = cli_rpc_pipe_open_schannel_with_key(
1236 cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
1237 DCERPC_AUTH_LEVEL_PRIVACY,
1238 netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd);
1240 cli_shutdown(cli);
1242 if (!NT_STATUS_IS_OK(status)) {
1243 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1244 "on netlogon pipe to server %s for domain %s. "
1245 "Error was %s\n",
1246 smbXcli_conn_remote_name(cli->conn),
1247 netbios_domain_name, nt_errstr(status)));
1248 return status;
1251 return NT_STATUS_OK;
1254 /****************************************************************
1255 ****************************************************************/
1257 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1258 struct libnet_JoinCtx *r)
1260 NTSTATUS status;
1262 status = libnet_join_ok(r->out.netbios_domain_name,
1263 r->in.machine_name,
1264 r->in.dc_name);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 libnet_join_set_error_string(mem_ctx, r,
1267 "failed to verify domain membership after joining: %s",
1268 get_friendly_nt_error_msg(status));
1269 return WERR_SETUP_NOT_JOINED;
1272 return WERR_OK;
1275 /****************************************************************
1276 ****************************************************************/
1278 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1279 struct libnet_UnjoinCtx *r)
1281 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1282 return false;
1285 if (!secrets_delete_domain_sid(lp_workgroup())) {
1286 return false;
1289 return true;
1292 /****************************************************************
1293 ****************************************************************/
1295 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1296 struct libnet_UnjoinCtx *r)
1298 struct cli_state *cli = NULL;
1299 struct rpc_pipe_client *pipe_hnd = NULL;
1300 struct policy_handle sam_pol, domain_pol, user_pol;
1301 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1302 char *acct_name;
1303 uint32_t user_rid;
1304 struct lsa_String lsa_acct_name;
1305 struct samr_Ids user_rids;
1306 struct samr_Ids name_types;
1307 union samr_UserInfo *info = NULL;
1308 struct dcerpc_binding_handle *b = NULL;
1310 ZERO_STRUCT(sam_pol);
1311 ZERO_STRUCT(domain_pol);
1312 ZERO_STRUCT(user_pol);
1314 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1315 r->in.admin_account,
1316 r->in.admin_password,
1317 r->in.use_kerberos,
1318 &cli);
1319 if (!NT_STATUS_IS_OK(status)) {
1320 goto done;
1323 /* Open the domain */
1325 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
1326 &pipe_hnd);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1329 nt_errstr(status)));
1330 goto done;
1333 b = pipe_hnd->binding_handle;
1335 status = dcerpc_samr_Connect2(b, mem_ctx,
1336 pipe_hnd->desthost,
1337 SEC_FLAG_MAXIMUM_ALLOWED,
1338 &sam_pol,
1339 &result);
1340 if (!NT_STATUS_IS_OK(status)) {
1341 goto done;
1343 if (!NT_STATUS_IS_OK(result)) {
1344 status = result;
1345 goto done;
1348 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1349 &sam_pol,
1350 SEC_FLAG_MAXIMUM_ALLOWED,
1351 r->in.domain_sid,
1352 &domain_pol,
1353 &result);
1354 if (!NT_STATUS_IS_OK(status)) {
1355 goto done;
1357 if (!NT_STATUS_IS_OK(result)) {
1358 status = result;
1359 goto done;
1362 /* Create domain user */
1364 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1365 strlower_m(acct_name);
1367 init_lsa_String(&lsa_acct_name, acct_name);
1369 status = dcerpc_samr_LookupNames(b, mem_ctx,
1370 &domain_pol,
1372 &lsa_acct_name,
1373 &user_rids,
1374 &name_types,
1375 &result);
1377 if (!NT_STATUS_IS_OK(status)) {
1378 goto done;
1380 if (!NT_STATUS_IS_OK(result)) {
1381 status = result;
1382 goto done;
1385 if (name_types.ids[0] != SID_NAME_USER) {
1386 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1387 name_types.ids[0]));
1388 status = NT_STATUS_INVALID_WORKSTATION;
1389 goto done;
1392 user_rid = user_rids.ids[0];
1394 /* Open handle on user */
1396 status = dcerpc_samr_OpenUser(b, mem_ctx,
1397 &domain_pol,
1398 SEC_FLAG_MAXIMUM_ALLOWED,
1399 user_rid,
1400 &user_pol,
1401 &result);
1402 if (!NT_STATUS_IS_OK(status)) {
1403 goto done;
1405 if (!NT_STATUS_IS_OK(result)) {
1406 status = result;
1407 goto done;
1410 /* Get user info */
1412 status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1413 &user_pol,
1415 &info,
1416 &result);
1417 if (!NT_STATUS_IS_OK(status)) {
1418 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1419 goto done;
1421 if (!NT_STATUS_IS_OK(result)) {
1422 status = result;
1423 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1424 goto done;
1427 /* now disable and setuser info */
1429 info->info16.acct_flags |= ACB_DISABLED;
1431 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1432 &user_pol,
1434 info,
1435 &result);
1436 if (!NT_STATUS_IS_OK(status)) {
1437 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1438 goto done;
1440 if (!NT_STATUS_IS_OK(result)) {
1441 status = result;
1442 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1443 goto done;
1445 status = result;
1446 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1448 done:
1449 if (pipe_hnd && b) {
1450 if (is_valid_policy_hnd(&domain_pol)) {
1451 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1453 if (is_valid_policy_hnd(&sam_pol)) {
1454 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1456 TALLOC_FREE(pipe_hnd);
1459 if (cli) {
1460 cli_shutdown(cli);
1463 return status;
1466 /****************************************************************
1467 ****************************************************************/
1469 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1471 WERROR werr = WERR_OK;
1472 sbcErr err;
1473 struct smbconf_ctx *ctx;
1475 err = smbconf_init_reg(r, &ctx, NULL);
1476 if (!SBC_ERROR_IS_OK(err)) {
1477 werr = WERR_NO_SUCH_SERVICE;
1478 goto done;
1481 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1483 err = smbconf_set_global_parameter(ctx, "security", "user");
1484 if (!SBC_ERROR_IS_OK(err)) {
1485 werr = WERR_NO_SUCH_SERVICE;
1486 goto done;
1489 err = smbconf_set_global_parameter(ctx, "workgroup",
1490 r->in.domain_name);
1491 if (!SBC_ERROR_IS_OK(err)) {
1492 werr = WERR_NO_SUCH_SERVICE;
1493 goto done;
1496 smbconf_delete_global_parameter(ctx, "realm");
1497 goto done;
1500 err = smbconf_set_global_parameter(ctx, "security", "domain");
1501 if (!SBC_ERROR_IS_OK(err)) {
1502 werr = WERR_NO_SUCH_SERVICE;
1503 goto done;
1506 err = smbconf_set_global_parameter(ctx, "workgroup",
1507 r->out.netbios_domain_name);
1508 if (!SBC_ERROR_IS_OK(err)) {
1509 werr = WERR_NO_SUCH_SERVICE;
1510 goto done;
1513 if (r->out.domain_is_ad) {
1514 err = smbconf_set_global_parameter(ctx, "security", "ads");
1515 if (!SBC_ERROR_IS_OK(err)) {
1516 werr = WERR_NO_SUCH_SERVICE;
1517 goto done;
1520 err = smbconf_set_global_parameter(ctx, "realm",
1521 r->out.dns_domain_name);
1522 if (!SBC_ERROR_IS_OK(err)) {
1523 werr = WERR_NO_SUCH_SERVICE;
1524 goto done;
1528 done:
1529 smbconf_shutdown(ctx);
1530 return werr;
1533 /****************************************************************
1534 ****************************************************************/
1536 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1538 WERROR werr = WERR_OK;
1539 sbcErr err;
1540 struct smbconf_ctx *ctx;
1542 err = smbconf_init_reg(r, &ctx, NULL);
1543 if (!SBC_ERROR_IS_OK(err)) {
1544 werr = WERR_NO_SUCH_SERVICE;
1545 goto done;
1548 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1550 err = smbconf_set_global_parameter(ctx, "security", "user");
1551 if (!SBC_ERROR_IS_OK(err)) {
1552 werr = WERR_NO_SUCH_SERVICE;
1553 goto done;
1556 err = smbconf_delete_global_parameter(ctx, "workgroup");
1557 if (!SBC_ERROR_IS_OK(err)) {
1558 werr = WERR_NO_SUCH_SERVICE;
1559 goto done;
1562 smbconf_delete_global_parameter(ctx, "realm");
1565 done:
1566 smbconf_shutdown(ctx);
1567 return werr;
1570 /****************************************************************
1571 ****************************************************************/
1573 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1575 WERROR werr;
1577 if (!W_ERROR_IS_OK(r->out.result)) {
1578 return r->out.result;
1581 if (!r->in.modify_config) {
1582 return WERR_OK;
1585 werr = do_join_modify_vals_config(r);
1586 if (!W_ERROR_IS_OK(werr)) {
1587 return werr;
1590 lp_load_global(get_dyn_CONFIGFILE());
1592 r->out.modified_config = true;
1593 r->out.result = werr;
1595 return werr;
1598 /****************************************************************
1599 ****************************************************************/
1601 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1603 WERROR werr;
1605 if (!W_ERROR_IS_OK(r->out.result)) {
1606 return r->out.result;
1609 if (!r->in.modify_config) {
1610 return WERR_OK;
1613 werr = do_unjoin_modify_vals_config(r);
1614 if (!W_ERROR_IS_OK(werr)) {
1615 return werr;
1618 lp_load_global(get_dyn_CONFIGFILE());
1620 r->out.modified_config = true;
1621 r->out.result = werr;
1623 return werr;
1626 /****************************************************************
1627 ****************************************************************/
1629 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1630 const char *domain_str,
1631 const char **domain_p,
1632 const char **dc_p)
1634 char *domain = NULL;
1635 char *dc = NULL;
1636 const char *p = NULL;
1638 if (!domain_str || !domain_p || !dc_p) {
1639 return false;
1642 p = strchr_m(domain_str, '\\');
1644 if (p != NULL) {
1645 domain = talloc_strndup(mem_ctx, domain_str,
1646 PTR_DIFF(p, domain_str));
1647 dc = talloc_strdup(mem_ctx, p+1);
1648 if (!dc) {
1649 return false;
1651 } else {
1652 domain = talloc_strdup(mem_ctx, domain_str);
1653 dc = NULL;
1655 if (!domain) {
1656 return false;
1659 *domain_p = domain;
1661 if (!*dc_p && dc) {
1662 *dc_p = dc;
1665 return true;
1668 /****************************************************************
1669 ****************************************************************/
1671 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1672 struct libnet_JoinCtx *r)
1674 if (!r->in.domain_name) {
1675 libnet_join_set_error_string(mem_ctx, r,
1676 "No domain name defined");
1677 return WERR_INVALID_PARAM;
1680 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1681 &r->in.domain_name,
1682 &r->in.dc_name)) {
1683 libnet_join_set_error_string(mem_ctx, r,
1684 "Failed to parse domain name");
1685 return WERR_INVALID_PARAM;
1688 if (IS_DC) {
1689 return WERR_SETUP_DOMAIN_CONTROLLER;
1692 if (!secrets_init()) {
1693 libnet_join_set_error_string(mem_ctx, r,
1694 "Unable to open secrets database");
1695 return WERR_CAN_NOT_COMPLETE;
1698 return WERR_OK;
1701 /****************************************************************
1702 ****************************************************************/
1704 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1706 NTSTATUS status;
1708 /* Try adding dom admins to builtin\admins. Only log failures. */
1709 status = create_builtin_administrators(domain_sid);
1710 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1711 DEBUG(10,("Unable to auto-add domain administrators to "
1712 "BUILTIN\\Administrators during join because "
1713 "winbindd must be running.\n"));
1714 } else if (!NT_STATUS_IS_OK(status)) {
1715 DEBUG(5, ("Failed to auto-add domain administrators to "
1716 "BUILTIN\\Administrators during join: %s\n",
1717 nt_errstr(status)));
1720 /* Try adding dom users to builtin\users. Only log failures. */
1721 status = create_builtin_users(domain_sid);
1722 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1723 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1724 "during join because winbindd must be running.\n"));
1725 } else if (!NT_STATUS_IS_OK(status)) {
1726 DEBUG(5, ("Failed to auto-add domain administrators to "
1727 "BUILTIN\\Administrators during join: %s\n",
1728 nt_errstr(status)));
1732 /****************************************************************
1733 ****************************************************************/
1735 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1736 struct libnet_JoinCtx *r)
1738 WERROR werr;
1740 if (!W_ERROR_IS_OK(r->out.result)) {
1741 return r->out.result;
1744 werr = do_JoinConfig(r);
1745 if (!W_ERROR_IS_OK(werr)) {
1746 return werr;
1749 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1750 return WERR_OK;
1753 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1754 if (r->out.dns_domain_name) {
1755 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1758 #ifdef HAVE_ADS
1759 if (r->out.domain_is_ad &&
1760 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1761 ADS_STATUS ads_status;
1763 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1764 if (!ADS_ERR_OK(ads_status)) {
1765 return WERR_GENERAL_FAILURE;
1768 #endif /* HAVE_ADS */
1770 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1772 return WERR_OK;
1775 /****************************************************************
1776 ****************************************************************/
1778 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1780 if (r->in.ads) {
1781 ads_destroy(&r->in.ads);
1784 return 0;
1787 /****************************************************************
1788 ****************************************************************/
1790 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1792 if (r->in.ads) {
1793 ads_destroy(&r->in.ads);
1796 return 0;
1799 /****************************************************************
1800 ****************************************************************/
1802 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1803 struct libnet_JoinCtx **r)
1805 struct libnet_JoinCtx *ctx;
1807 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1808 if (!ctx) {
1809 return WERR_NOMEM;
1812 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1814 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
1815 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1817 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1819 *r = ctx;
1821 return WERR_OK;
1824 /****************************************************************
1825 ****************************************************************/
1827 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1828 struct libnet_UnjoinCtx **r)
1830 struct libnet_UnjoinCtx *ctx;
1832 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1833 if (!ctx) {
1834 return WERR_NOMEM;
1837 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1839 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
1840 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1842 *r = ctx;
1844 return WERR_OK;
1847 /****************************************************************
1848 ****************************************************************/
1850 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
1851 struct libnet_JoinCtx *r)
1853 bool valid_security = false;
1854 bool valid_workgroup = false;
1855 bool valid_realm = false;
1857 /* check if configuration is already set correctly */
1859 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
1861 switch (r->out.domain_is_ad) {
1862 case false:
1863 valid_security = (lp_security() == SEC_DOMAIN);
1864 if (valid_workgroup && valid_security) {
1865 /* nothing to be done */
1866 return WERR_OK;
1868 break;
1869 case true:
1870 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
1871 switch (lp_security()) {
1872 case SEC_DOMAIN:
1873 case SEC_ADS:
1874 valid_security = true;
1877 if (valid_workgroup && valid_realm && valid_security) {
1878 /* nothing to be done */
1879 return WERR_OK;
1881 break;
1884 /* check if we are supposed to manipulate configuration */
1886 if (!r->in.modify_config) {
1888 char *wrong_conf = talloc_strdup(mem_ctx, "");
1890 if (!valid_workgroup) {
1891 wrong_conf = talloc_asprintf_append(wrong_conf,
1892 "\"workgroup\" set to '%s', should be '%s'",
1893 lp_workgroup(), r->out.netbios_domain_name);
1894 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1897 if (!valid_realm) {
1898 wrong_conf = talloc_asprintf_append(wrong_conf,
1899 "\"realm\" set to '%s', should be '%s'",
1900 lp_realm(), r->out.dns_domain_name);
1901 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1904 if (!valid_security) {
1905 const char *sec = NULL;
1906 switch (lp_security()) {
1907 case SEC_USER: sec = "user"; break;
1908 case SEC_DOMAIN: sec = "domain"; break;
1909 case SEC_ADS: sec = "ads"; break;
1911 wrong_conf = talloc_asprintf_append(wrong_conf,
1912 "\"security\" set to '%s', should be %s",
1913 sec, r->out.domain_is_ad ?
1914 "either 'domain' or 'ads'" : "'domain'");
1915 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1918 libnet_join_set_error_string(mem_ctx, r,
1919 "Invalid configuration (%s) and configuration modification "
1920 "was not requested", wrong_conf);
1921 return WERR_CAN_NOT_COMPLETE;
1924 /* check if we are able to manipulate configuration */
1926 if (!lp_config_backend_is_registry()) {
1927 libnet_join_set_error_string(mem_ctx, r,
1928 "Configuration manipulation requested but not "
1929 "supported by backend");
1930 return WERR_NOT_SUPPORTED;
1933 return WERR_OK;
1936 /****************************************************************
1937 ****************************************************************/
1939 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1940 struct libnet_JoinCtx *r)
1942 NTSTATUS status;
1943 WERROR werr;
1944 struct cli_state *cli = NULL;
1945 #ifdef HAVE_ADS
1946 ADS_STATUS ads_status;
1947 #endif /* HAVE_ADS */
1949 if (!r->in.dc_name) {
1950 struct netr_DsRGetDCNameInfo *info;
1951 const char *dc;
1952 status = dsgetdcname(mem_ctx,
1953 r->in.msg_ctx,
1954 r->in.domain_name,
1955 NULL,
1956 NULL,
1957 DS_FORCE_REDISCOVERY |
1958 DS_DIRECTORY_SERVICE_REQUIRED |
1959 DS_WRITABLE_REQUIRED |
1960 DS_RETURN_DNS_NAME,
1961 &info);
1962 if (!NT_STATUS_IS_OK(status)) {
1963 libnet_join_set_error_string(mem_ctx, r,
1964 "failed to find DC for domain %s",
1965 r->in.domain_name,
1966 get_friendly_nt_error_msg(status));
1967 return WERR_DCNOTFOUND;
1970 dc = strip_hostname(info->dc_unc);
1971 r->in.dc_name = talloc_strdup(mem_ctx, dc);
1972 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1975 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
1976 if (!NT_STATUS_IS_OK(status)) {
1977 libnet_join_set_error_string(mem_ctx, r,
1978 "failed to lookup DC info for domain '%s' over rpc: %s",
1979 r->in.domain_name, get_friendly_nt_error_msg(status));
1980 return ntstatus_to_werror(status);
1983 werr = libnet_join_check_config(mem_ctx, r);
1984 if (!W_ERROR_IS_OK(werr)) {
1985 goto done;
1988 #ifdef HAVE_ADS
1990 create_local_private_krb5_conf_for_domain(
1991 r->out.dns_domain_name, r->out.netbios_domain_name,
1992 NULL, smbXcli_conn_remote_sockaddr(cli->conn),
1993 smbXcli_conn_remote_name(cli->conn));
1995 if (r->out.domain_is_ad && r->in.account_ou &&
1996 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1998 ads_status = libnet_join_connect_ads(mem_ctx, r);
1999 if (!ADS_ERR_OK(ads_status)) {
2000 return WERR_DEFAULT_JOIN_REQUIRED;
2003 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2004 if (!ADS_ERR_OK(ads_status)) {
2005 libnet_join_set_error_string(mem_ctx, r,
2006 "failed to precreate account in ou %s: %s",
2007 r->in.account_ou,
2008 ads_errstr(ads_status));
2009 return WERR_DEFAULT_JOIN_REQUIRED;
2012 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2014 #endif /* HAVE_ADS */
2016 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2017 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2018 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2019 } else {
2020 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2022 if (!NT_STATUS_IS_OK(status)) {
2023 libnet_join_set_error_string(mem_ctx, r,
2024 "failed to join domain '%s' over rpc: %s",
2025 r->in.domain_name, get_friendly_nt_error_msg(status));
2026 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2027 return WERR_SETUP_ALREADY_JOINED;
2029 werr = ntstatus_to_werror(status);
2030 goto done;
2033 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2034 werr = WERR_SETUP_NOT_JOINED;
2035 goto done;
2038 werr = WERR_OK;
2040 done:
2041 if (cli) {
2042 cli_shutdown(cli);
2045 return werr;
2048 /****************************************************************
2049 ****************************************************************/
2051 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2052 struct libnet_JoinCtx *r)
2054 WERROR werr;
2055 struct libnet_UnjoinCtx *u = NULL;
2057 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2058 if (!W_ERROR_IS_OK(werr)) {
2059 return werr;
2062 u->in.debug = r->in.debug;
2063 u->in.dc_name = r->in.dc_name;
2064 u->in.domain_name = r->in.domain_name;
2065 u->in.admin_account = r->in.admin_account;
2066 u->in.admin_password = r->in.admin_password;
2067 u->in.modify_config = r->in.modify_config;
2068 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2069 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2071 werr = libnet_Unjoin(mem_ctx, u);
2072 TALLOC_FREE(u);
2074 return werr;
2077 /****************************************************************
2078 ****************************************************************/
2080 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2081 struct libnet_JoinCtx *r)
2083 WERROR werr;
2085 if (r->in.debug) {
2086 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2089 ZERO_STRUCT(r->out);
2091 werr = libnet_join_pre_processing(mem_ctx, r);
2092 if (!W_ERROR_IS_OK(werr)) {
2093 goto done;
2096 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2097 werr = libnet_DomainJoin(mem_ctx, r);
2098 if (!W_ERROR_IS_OK(werr)) {
2099 goto done;
2103 werr = libnet_join_post_processing(mem_ctx, r);
2104 if (!W_ERROR_IS_OK(werr)) {
2105 goto done;
2108 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2109 werr = libnet_join_post_verify(mem_ctx, r);
2110 if (!W_ERROR_IS_OK(werr)) {
2111 libnet_join_rollback(mem_ctx, r);
2115 done:
2116 r->out.result = werr;
2118 if (r->in.debug) {
2119 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2121 return werr;
2124 /****************************************************************
2125 ****************************************************************/
2127 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2128 struct libnet_UnjoinCtx *r)
2130 NTSTATUS status;
2132 if (!r->in.domain_sid) {
2133 struct dom_sid sid;
2134 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2135 libnet_unjoin_set_error_string(mem_ctx, r,
2136 "Unable to fetch domain sid: are we joined?");
2137 return WERR_SETUP_NOT_JOINED;
2139 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2140 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2143 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2144 !r->in.delete_machine_account) {
2145 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2146 return WERR_OK;
2149 if (!r->in.dc_name) {
2150 struct netr_DsRGetDCNameInfo *info;
2151 const char *dc;
2152 status = dsgetdcname(mem_ctx,
2153 r->in.msg_ctx,
2154 r->in.domain_name,
2155 NULL,
2156 NULL,
2157 DS_DIRECTORY_SERVICE_REQUIRED |
2158 DS_WRITABLE_REQUIRED |
2159 DS_RETURN_DNS_NAME,
2160 &info);
2161 if (!NT_STATUS_IS_OK(status)) {
2162 libnet_unjoin_set_error_string(mem_ctx, r,
2163 "failed to find DC for domain %s",
2164 r->in.domain_name,
2165 get_friendly_nt_error_msg(status));
2166 return WERR_DCNOTFOUND;
2169 dc = strip_hostname(info->dc_unc);
2170 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2171 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2174 #ifdef HAVE_ADS
2175 /* for net ads leave, try to delete the account. If it works,
2176 no sense in disabling. If it fails, we can still try to
2177 disable it. jmcd */
2179 if (r->in.delete_machine_account) {
2180 ADS_STATUS ads_status;
2181 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2182 if (ADS_ERR_OK(ads_status)) {
2183 /* dirty hack */
2184 r->out.dns_domain_name =
2185 talloc_strdup(mem_ctx,
2186 r->in.ads->server.realm);
2187 ads_status =
2188 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2190 if (!ADS_ERR_OK(ads_status)) {
2191 libnet_unjoin_set_error_string(mem_ctx, r,
2192 "failed to remove machine account from AD: %s",
2193 ads_errstr(ads_status));
2194 } else {
2195 r->out.deleted_machine_account = true;
2196 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2197 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2198 return WERR_OK;
2201 #endif /* HAVE_ADS */
2203 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2204 "disable". */
2205 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2206 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2207 if (!NT_STATUS_IS_OK(status)) {
2208 libnet_unjoin_set_error_string(mem_ctx, r,
2209 "failed to disable machine account via rpc: %s",
2210 get_friendly_nt_error_msg(status));
2211 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2212 return WERR_SETUP_NOT_JOINED;
2214 return ntstatus_to_werror(status);
2217 r->out.disabled_machine_account = true;
2220 /* If disable succeeded or was not requested at all, we
2221 should be getting rid of our end of things */
2223 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2225 return WERR_OK;
2228 /****************************************************************
2229 ****************************************************************/
2231 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2232 struct libnet_UnjoinCtx *r)
2234 if (!r->in.domain_name) {
2235 libnet_unjoin_set_error_string(mem_ctx, r,
2236 "No domain name defined");
2237 return WERR_INVALID_PARAM;
2240 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2241 &r->in.domain_name,
2242 &r->in.dc_name)) {
2243 libnet_unjoin_set_error_string(mem_ctx, r,
2244 "Failed to parse domain name");
2245 return WERR_INVALID_PARAM;
2248 if (IS_DC) {
2249 return WERR_SETUP_DOMAIN_CONTROLLER;
2252 if (!secrets_init()) {
2253 libnet_unjoin_set_error_string(mem_ctx, r,
2254 "Unable to open secrets database");
2255 return WERR_CAN_NOT_COMPLETE;
2258 return WERR_OK;
2261 /****************************************************************
2262 ****************************************************************/
2264 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2265 struct libnet_UnjoinCtx *r)
2267 saf_delete(r->out.netbios_domain_name);
2268 saf_delete(r->out.dns_domain_name);
2270 return libnet_unjoin_config(r);
2273 /****************************************************************
2274 ****************************************************************/
2276 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2277 struct libnet_UnjoinCtx *r)
2279 WERROR werr;
2281 if (r->in.debug) {
2282 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2285 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2286 if (!W_ERROR_IS_OK(werr)) {
2287 goto done;
2290 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2291 werr = libnet_DomainUnjoin(mem_ctx, r);
2292 if (!W_ERROR_IS_OK(werr)) {
2293 libnet_unjoin_config(r);
2294 goto done;
2298 werr = libnet_unjoin_post_processing(mem_ctx, r);
2299 if (!W_ERROR_IS_OK(werr)) {
2300 goto done;
2303 done:
2304 r->out.result = werr;
2306 if (r->in.debug) {
2307 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2310 return werr;