s3-rpc_server: Created a per connection spoolss pipe.
[Samba/ekacnet.git] / source3 / libnet / libnet_join.c
bloba4aecd21126d446436a4e5ffd2fd811bdc137390
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 "libnet/libnet.h"
23 #include "libcli/auth/libcli_auth.h"
24 #include "../librpc/gen_ndr/cli_samr.h"
25 #include "rpc_client/init_samr.h"
26 #include "../librpc/gen_ndr/cli_lsa.h"
27 #include "rpc_client/cli_lsarpc.h"
28 #include "../librpc/gen_ndr/cli_netlogon.h"
29 #include "rpc_client/cli_netlogon.h"
30 #include "lib/smbconf/smbconf.h"
31 #include "lib/smbconf/smbconf_reg.h"
33 /****************************************************************
34 ****************************************************************/
36 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
37 do { \
38 char *str = NULL; \
39 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
40 DEBUG(1,("libnet_Join:\n%s", str)); \
41 TALLOC_FREE(str); \
42 } while (0)
44 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
45 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
46 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
47 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
49 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
50 do { \
51 char *str = NULL; \
52 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
53 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
54 TALLOC_FREE(str); \
55 } while (0)
57 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
58 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
59 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
60 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
62 /****************************************************************
63 ****************************************************************/
65 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
66 struct libnet_JoinCtx *r,
67 const char *format, ...)
69 va_list args;
71 if (r->out.error_string) {
72 return;
75 va_start(args, format);
76 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
77 va_end(args);
80 /****************************************************************
81 ****************************************************************/
83 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
84 struct libnet_UnjoinCtx *r,
85 const char *format, ...)
87 va_list args;
89 if (r->out.error_string) {
90 return;
93 va_start(args, format);
94 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
95 va_end(args);
98 #ifdef WITH_ADS
100 /****************************************************************
101 ****************************************************************/
103 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
104 const char *netbios_domain_name,
105 const char *dc_name,
106 const char *user_name,
107 const char *password,
108 ADS_STRUCT **ads)
110 ADS_STATUS status;
111 ADS_STRUCT *my_ads = NULL;
113 my_ads = ads_init(dns_domain_name,
114 netbios_domain_name,
115 dc_name);
116 if (!my_ads) {
117 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
120 if (user_name) {
121 SAFE_FREE(my_ads->auth.user_name);
122 my_ads->auth.user_name = SMB_STRDUP(user_name);
125 if (password) {
126 SAFE_FREE(my_ads->auth.password);
127 my_ads->auth.password = SMB_STRDUP(password);
130 status = ads_connect_user_creds(my_ads);
131 if (!ADS_ERR_OK(status)) {
132 ads_destroy(&my_ads);
133 return status;
136 *ads = my_ads;
137 return ADS_SUCCESS;
140 /****************************************************************
141 ****************************************************************/
143 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
144 struct libnet_JoinCtx *r)
146 ADS_STATUS status;
148 status = libnet_connect_ads(r->out.dns_domain_name,
149 r->out.netbios_domain_name,
150 r->in.dc_name,
151 r->in.admin_account,
152 r->in.admin_password,
153 &r->in.ads);
154 if (!ADS_ERR_OK(status)) {
155 libnet_join_set_error_string(mem_ctx, r,
156 "failed to connect to AD: %s",
157 ads_errstr(status));
158 return status;
161 if (!r->out.netbios_domain_name) {
162 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
163 r->in.ads->server.workgroup);
164 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
167 if (!r->out.dns_domain_name) {
168 r->out.dns_domain_name = talloc_strdup(mem_ctx,
169 r->in.ads->config.realm);
170 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
173 r->out.domain_is_ad = true;
175 return ADS_SUCCESS;
178 /****************************************************************
179 ****************************************************************/
181 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
182 struct libnet_UnjoinCtx *r)
184 ADS_STATUS status;
186 status = libnet_connect_ads(r->in.domain_name,
187 r->in.domain_name,
188 r->in.dc_name,
189 r->in.admin_account,
190 r->in.admin_password,
191 &r->in.ads);
192 if (!ADS_ERR_OK(status)) {
193 libnet_unjoin_set_error_string(mem_ctx, r,
194 "failed to connect to AD: %s",
195 ads_errstr(status));
198 return status;
201 /****************************************************************
202 join a domain using ADS (LDAP mods)
203 ****************************************************************/
205 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
206 struct libnet_JoinCtx *r)
208 ADS_STATUS status;
209 LDAPMessage *res = NULL;
210 const char *attrs[] = { "dn", NULL };
211 bool moved = false;
213 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
214 if (!ADS_ERR_OK(status)) {
215 return status;
218 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
219 if (!ADS_ERR_OK(status)) {
220 return status;
223 if (ads_count_replies(r->in.ads, res) != 1) {
224 ads_msgfree(r->in.ads, res);
225 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
228 ads_msgfree(r->in.ads, res);
230 /* Attempt to create the machine account and bail if this fails.
231 Assume that the admin wants exactly what they requested */
233 status = ads_create_machine_acct(r->in.ads,
234 r->in.machine_name,
235 r->in.account_ou);
237 if (ADS_ERR_OK(status)) {
238 DEBUG(1,("machine account creation created\n"));
239 return status;
240 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
241 (status.err.rc == LDAP_ALREADY_EXISTS)) {
242 status = ADS_SUCCESS;
245 if (!ADS_ERR_OK(status)) {
246 DEBUG(1,("machine account creation failed\n"));
247 return status;
250 status = ads_move_machine_acct(r->in.ads,
251 r->in.machine_name,
252 r->in.account_ou,
253 &moved);
254 if (!ADS_ERR_OK(status)) {
255 DEBUG(1,("failure to locate/move pre-existing "
256 "machine account\n"));
257 return status;
260 DEBUG(1,("The machine account %s the specified OU.\n",
261 moved ? "was moved into" : "already exists in"));
263 return status;
266 /****************************************************************
267 ****************************************************************/
269 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
270 struct libnet_UnjoinCtx *r)
272 ADS_STATUS status;
274 if (!r->in.ads) {
275 status = libnet_unjoin_connect_ads(mem_ctx, r);
276 if (!ADS_ERR_OK(status)) {
277 libnet_unjoin_set_error_string(mem_ctx, r,
278 "failed to connect to AD: %s",
279 ads_errstr(status));
280 return status;
284 status = ads_leave_realm(r->in.ads, r->in.machine_name);
285 if (!ADS_ERR_OK(status)) {
286 libnet_unjoin_set_error_string(mem_ctx, r,
287 "failed to leave realm: %s",
288 ads_errstr(status));
289 return status;
292 return ADS_SUCCESS;
295 /****************************************************************
296 ****************************************************************/
298 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
299 struct libnet_JoinCtx *r)
301 ADS_STATUS status;
302 LDAPMessage *res = NULL;
303 char *dn = NULL;
305 if (!r->in.machine_name) {
306 return ADS_ERROR(LDAP_NO_MEMORY);
309 status = ads_find_machine_acct(r->in.ads,
310 &res,
311 r->in.machine_name);
312 if (!ADS_ERR_OK(status)) {
313 return status;
316 if (ads_count_replies(r->in.ads, res) != 1) {
317 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
318 goto done;
321 dn = ads_get_dn(r->in.ads, mem_ctx, res);
322 if (!dn) {
323 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
324 goto done;
327 r->out.dn = talloc_strdup(mem_ctx, dn);
328 if (!r->out.dn) {
329 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
330 goto done;
333 done:
334 ads_msgfree(r->in.ads, res);
335 TALLOC_FREE(dn);
337 return status;
340 /****************************************************************
341 Set a machines dNSHostName and servicePrincipalName attributes
342 ****************************************************************/
344 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
345 struct libnet_JoinCtx *r)
347 ADS_STATUS status;
348 ADS_MODLIST mods;
349 fstring my_fqdn;
350 const char *spn_array[3] = {NULL, NULL, NULL};
351 char *spn = NULL;
353 /* Find our DN */
355 status = libnet_join_find_machine_acct(mem_ctx, r);
356 if (!ADS_ERR_OK(status)) {
357 return status;
360 /* Windows only creates HOST/shortname & HOST/fqdn. */
362 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
363 if (!spn) {
364 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
366 strupper_m(spn);
367 spn_array[0] = spn;
369 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
370 || (strchr(my_fqdn, '.') == NULL)) {
371 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
372 r->out.dns_domain_name);
375 strlower_m(my_fqdn);
377 if (!strequal(my_fqdn, r->in.machine_name)) {
378 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
379 if (!spn) {
380 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
382 spn_array[1] = spn;
385 mods = ads_init_mods(mem_ctx);
386 if (!mods) {
387 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
390 /* fields of primary importance */
392 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
393 if (!ADS_ERR_OK(status)) {
394 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
397 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
398 spn_array);
399 if (!ADS_ERR_OK(status)) {
400 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
403 return ads_gen_mod(r->in.ads, r->out.dn, mods);
406 /****************************************************************
407 ****************************************************************/
409 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
410 struct libnet_JoinCtx *r)
412 ADS_STATUS status;
413 ADS_MODLIST mods;
415 if (!r->in.create_upn) {
416 return ADS_SUCCESS;
419 /* Find our DN */
421 status = libnet_join_find_machine_acct(mem_ctx, r);
422 if (!ADS_ERR_OK(status)) {
423 return status;
426 if (!r->in.upn) {
427 r->in.upn = talloc_asprintf(mem_ctx,
428 "host/%s@%s",
429 r->in.machine_name,
430 r->out.dns_domain_name);
431 if (!r->in.upn) {
432 return ADS_ERROR(LDAP_NO_MEMORY);
436 /* now do the mods */
438 mods = ads_init_mods(mem_ctx);
439 if (!mods) {
440 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
443 /* fields of primary importance */
445 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
446 if (!ADS_ERR_OK(status)) {
447 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
450 return ads_gen_mod(r->in.ads, r->out.dn, mods);
454 /****************************************************************
455 ****************************************************************/
457 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
458 struct libnet_JoinCtx *r)
460 ADS_STATUS status;
461 ADS_MODLIST mods;
462 char *os_sp = NULL;
464 if (!r->in.os_name || !r->in.os_version ) {
465 return ADS_SUCCESS;
468 /* Find our DN */
470 status = libnet_join_find_machine_acct(mem_ctx, r);
471 if (!ADS_ERR_OK(status)) {
472 return status;
475 /* now do the mods */
477 mods = ads_init_mods(mem_ctx);
478 if (!mods) {
479 return ADS_ERROR(LDAP_NO_MEMORY);
482 os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
483 if (!os_sp) {
484 return ADS_ERROR(LDAP_NO_MEMORY);
487 /* fields of primary importance */
489 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
490 r->in.os_name);
491 if (!ADS_ERR_OK(status)) {
492 return status;
495 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
496 r->in.os_version);
497 if (!ADS_ERR_OK(status)) {
498 return status;
501 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
502 os_sp);
503 if (!ADS_ERR_OK(status)) {
504 return status;
507 return ads_gen_mod(r->in.ads, r->out.dn, mods);
510 /****************************************************************
511 ****************************************************************/
513 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
514 struct libnet_JoinCtx *r)
516 if (!USE_SYSTEM_KEYTAB) {
517 return true;
520 if (ads_keytab_create_default(r->in.ads) != 0) {
521 return false;
524 return true;
527 /****************************************************************
528 ****************************************************************/
530 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
531 struct libnet_JoinCtx *r)
533 uint32_t domain_func;
534 ADS_STATUS status;
535 const char *salt = NULL;
536 char *std_salt = NULL;
538 status = ads_domain_func_level(r->in.ads, &domain_func);
539 if (!ADS_ERR_OK(status)) {
540 libnet_join_set_error_string(mem_ctx, r,
541 "failed to determine domain functional level: %s",
542 ads_errstr(status));
543 return false;
546 /* go ahead and setup the default salt */
548 std_salt = kerberos_standard_des_salt();
549 if (!std_salt) {
550 libnet_join_set_error_string(mem_ctx, r,
551 "failed to obtain standard DES salt");
552 return false;
555 salt = talloc_strdup(mem_ctx, std_salt);
556 if (!salt) {
557 return false;
560 SAFE_FREE(std_salt);
562 /* if it's a Windows functional domain, we have to look for the UPN */
564 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
565 char *upn;
567 upn = ads_get_upn(r->in.ads, mem_ctx,
568 r->in.machine_name);
569 if (upn) {
570 salt = talloc_strdup(mem_ctx, upn);
571 if (!salt) {
572 return false;
577 return kerberos_secrets_store_des_salt(salt);
580 /****************************************************************
581 ****************************************************************/
583 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
584 struct libnet_JoinCtx *r)
586 ADS_STATUS status;
588 if (!r->in.ads) {
589 status = libnet_join_connect_ads(mem_ctx, r);
590 if (!ADS_ERR_OK(status)) {
591 return status;
595 status = libnet_join_set_machine_spn(mem_ctx, r);
596 if (!ADS_ERR_OK(status)) {
597 libnet_join_set_error_string(mem_ctx, r,
598 "failed to set machine spn: %s",
599 ads_errstr(status));
600 return status;
603 status = libnet_join_set_os_attributes(mem_ctx, r);
604 if (!ADS_ERR_OK(status)) {
605 libnet_join_set_error_string(mem_ctx, r,
606 "failed to set machine os attributes: %s",
607 ads_errstr(status));
608 return status;
611 status = libnet_join_set_machine_upn(mem_ctx, r);
612 if (!ADS_ERR_OK(status)) {
613 libnet_join_set_error_string(mem_ctx, r,
614 "failed to set machine upn: %s",
615 ads_errstr(status));
616 return status;
619 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
620 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
623 if (!libnet_join_create_keytab(mem_ctx, r)) {
624 libnet_join_set_error_string(mem_ctx, r,
625 "failed to create kerberos keytab");
626 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
629 return ADS_SUCCESS;
631 #endif /* WITH_ADS */
633 /****************************************************************
634 Store the machine password and domain SID
635 ****************************************************************/
637 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
638 struct libnet_JoinCtx *r)
640 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
641 r->out.domain_sid))
643 DEBUG(1,("Failed to save domain sid\n"));
644 return false;
647 if (!secrets_store_machine_password(r->in.machine_password,
648 r->out.netbios_domain_name,
649 r->in.secure_channel_type))
651 DEBUG(1,("Failed to save machine password\n"));
652 return false;
655 return true;
658 /****************************************************************
659 Connect dc's IPC$ share
660 ****************************************************************/
662 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
663 const char *user,
664 const char *pass,
665 bool use_kerberos,
666 struct cli_state **cli)
668 int flags = 0;
670 if (use_kerberos) {
671 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
674 if (use_kerberos && pass) {
675 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
678 return cli_full_connection(cli, NULL,
680 NULL, 0,
681 "IPC$", "IPC",
682 user,
683 NULL,
684 pass,
685 flags,
686 Undefined, NULL);
689 /****************************************************************
690 Lookup domain dc's info
691 ****************************************************************/
693 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
694 struct libnet_JoinCtx *r,
695 struct cli_state **cli)
697 struct rpc_pipe_client *pipe_hnd = NULL;
698 struct policy_handle lsa_pol;
699 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
700 union lsa_PolicyInformation *info = NULL;
702 status = libnet_join_connect_dc_ipc(r->in.dc_name,
703 r->in.admin_account,
704 r->in.admin_password,
705 r->in.use_kerberos,
706 cli);
707 if (!NT_STATUS_IS_OK(status)) {
708 goto done;
711 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
712 &pipe_hnd);
713 if (!NT_STATUS_IS_OK(status)) {
714 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
715 nt_errstr(status)));
716 goto done;
719 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
720 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
721 if (!NT_STATUS_IS_OK(status)) {
722 goto done;
725 status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx,
726 &lsa_pol,
727 LSA_POLICY_INFO_DNS,
728 &info);
729 if (NT_STATUS_IS_OK(status)) {
730 r->out.domain_is_ad = true;
731 r->out.netbios_domain_name = info->dns.name.string;
732 r->out.dns_domain_name = info->dns.dns_domain.string;
733 r->out.forest_name = info->dns.dns_forest.string;
734 r->out.domain_sid = sid_dup_talloc(mem_ctx, info->dns.sid);
735 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
738 if (!NT_STATUS_IS_OK(status)) {
739 status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
740 &lsa_pol,
741 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
742 &info);
743 if (!NT_STATUS_IS_OK(status)) {
744 goto done;
747 r->out.netbios_domain_name = info->account_domain.name.string;
748 r->out.domain_sid = sid_dup_talloc(mem_ctx, info->account_domain.sid);
749 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
752 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
753 TALLOC_FREE(pipe_hnd);
755 done:
756 return status;
759 /****************************************************************
760 Do the domain join unsecure
761 ****************************************************************/
763 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
764 struct libnet_JoinCtx *r,
765 struct cli_state *cli)
767 struct rpc_pipe_client *pipe_hnd = NULL;
768 unsigned char orig_trust_passwd_hash[16];
769 unsigned char new_trust_passwd_hash[16];
770 fstring trust_passwd;
771 NTSTATUS status;
773 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
774 &pipe_hnd);
775 if (!NT_STATUS_IS_OK(status)) {
776 return status;
779 if (!r->in.machine_password) {
780 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
781 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
784 E_md4hash(r->in.machine_password, new_trust_passwd_hash);
786 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
787 fstrcpy(trust_passwd, r->in.admin_password);
788 strlower_m(trust_passwd);
791 * Machine names can be 15 characters, but the max length on
792 * a password is 14. --jerry
795 trust_passwd[14] = '\0';
797 E_md4hash(trust_passwd, orig_trust_passwd_hash);
799 status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx,
800 r->in.machine_name,
801 orig_trust_passwd_hash,
802 r->in.machine_password,
803 new_trust_passwd_hash,
804 r->in.secure_channel_type);
806 return status;
809 /****************************************************************
810 Do the domain join
811 ****************************************************************/
813 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
814 struct libnet_JoinCtx *r,
815 struct cli_state *cli)
817 struct rpc_pipe_client *pipe_hnd = NULL;
818 struct policy_handle sam_pol, domain_pol, user_pol;
819 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
820 char *acct_name;
821 struct lsa_String lsa_acct_name;
822 uint32_t user_rid;
823 uint32_t acct_flags = ACB_WSTRUST;
824 struct samr_Ids user_rids;
825 struct samr_Ids name_types;
826 union samr_UserInfo user_info;
828 struct samr_CryptPassword crypt_pwd;
829 struct samr_CryptPasswordEx crypt_pwd_ex;
831 ZERO_STRUCT(sam_pol);
832 ZERO_STRUCT(domain_pol);
833 ZERO_STRUCT(user_pol);
835 switch (r->in.secure_channel_type) {
836 case SEC_CHAN_WKSTA:
837 acct_flags = ACB_WSTRUST;
838 break;
839 case SEC_CHAN_BDC:
840 acct_flags = ACB_SVRTRUST;
841 break;
842 default:
843 return NT_STATUS_INVALID_PARAMETER;
846 if (!r->in.machine_password) {
847 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
848 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
851 /* Open the domain */
853 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
854 &pipe_hnd);
855 if (!NT_STATUS_IS_OK(status)) {
856 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
857 nt_errstr(status)));
858 goto done;
861 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
862 pipe_hnd->desthost,
863 SAMR_ACCESS_ENUM_DOMAINS
864 | SAMR_ACCESS_LOOKUP_DOMAIN,
865 &sam_pol);
866 if (!NT_STATUS_IS_OK(status)) {
867 goto done;
870 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
871 &sam_pol,
872 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
873 | SAMR_DOMAIN_ACCESS_CREATE_USER
874 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
875 r->out.domain_sid,
876 &domain_pol);
877 if (!NT_STATUS_IS_OK(status)) {
878 goto done;
881 /* Create domain user */
883 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
884 strlower_m(acct_name);
886 init_lsa_String(&lsa_acct_name, acct_name);
888 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
889 uint32_t access_desired =
890 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
891 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
892 SAMR_USER_ACCESS_SET_PASSWORD |
893 SAMR_USER_ACCESS_GET_ATTRIBUTES |
894 SAMR_USER_ACCESS_SET_ATTRIBUTES;
895 uint32_t access_granted = 0;
897 DEBUG(10,("Creating account with desired access mask: %d\n",
898 access_desired));
900 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
901 &domain_pol,
902 &lsa_acct_name,
903 acct_flags,
904 access_desired,
905 &user_pol,
906 &access_granted,
907 &user_rid);
908 if (!NT_STATUS_IS_OK(status) &&
909 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
911 DEBUG(10,("Creation of workstation account failed: %s\n",
912 nt_errstr(status)));
914 /* If NT_STATUS_ACCESS_DENIED then we have a valid
915 username/password combo but the user does not have
916 administrator access. */
918 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
919 libnet_join_set_error_string(mem_ctx, r,
920 "User specified does not have "
921 "administrator privileges");
924 goto done;
927 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
928 if (!(r->in.join_flags &
929 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
930 goto done;
934 /* We *must* do this.... don't ask... */
936 if (NT_STATUS_IS_OK(status)) {
937 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
941 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
942 &domain_pol,
944 &lsa_acct_name,
945 &user_rids,
946 &name_types);
947 if (!NT_STATUS_IS_OK(status)) {
948 goto done;
951 if (name_types.ids[0] != SID_NAME_USER) {
952 DEBUG(0,("%s is not a user account (type=%d)\n",
953 acct_name, name_types.ids[0]));
954 status = NT_STATUS_INVALID_WORKSTATION;
955 goto done;
958 user_rid = user_rids.ids[0];
960 /* Open handle on user */
962 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
963 &domain_pol,
964 SEC_FLAG_MAXIMUM_ALLOWED,
965 user_rid,
966 &user_pol);
967 if (!NT_STATUS_IS_OK(status)) {
968 goto done;
971 /* Fill in the additional account flags now */
973 acct_flags |= ACB_PWNOEXP;
974 if (r->out.domain_is_ad) {
975 #if !defined(ENCTYPE_ARCFOUR_HMAC)
976 acct_flags |= ACB_USE_DES_KEY_ONLY;
977 #endif
981 /* Set account flags on machine account */
982 ZERO_STRUCT(user_info.info16);
983 user_info.info16.acct_flags = acct_flags;
985 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
986 &user_pol,
988 &user_info);
990 if (!NT_STATUS_IS_OK(status)) {
992 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
993 &user_pol);
995 libnet_join_set_error_string(mem_ctx, r,
996 "Failed to set account flags for machine account (%s)\n",
997 nt_errstr(status));
998 goto done;
1001 /* Set password on machine account - first try level 26 */
1003 init_samr_CryptPasswordEx(r->in.machine_password,
1004 &cli->user_session_key,
1005 &crypt_pwd_ex);
1007 user_info.info26.password = crypt_pwd_ex;
1008 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1010 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1011 &user_pol,
1013 &user_info);
1015 if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
1017 /* retry with level 24 */
1019 init_samr_CryptPassword(r->in.machine_password,
1020 &cli->user_session_key,
1021 &crypt_pwd);
1023 user_info.info24.password = crypt_pwd;
1024 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1026 status = rpccli_samr_SetUserInfo2(pipe_hnd, mem_ctx,
1027 &user_pol,
1029 &user_info);
1032 if (!NT_STATUS_IS_OK(status)) {
1034 rpccli_samr_DeleteUser(pipe_hnd, mem_ctx,
1035 &user_pol);
1037 libnet_join_set_error_string(mem_ctx, r,
1038 "Failed to set password for machine account (%s)\n",
1039 nt_errstr(status));
1040 goto done;
1043 status = NT_STATUS_OK;
1045 done:
1046 if (!pipe_hnd) {
1047 return status;
1050 if (is_valid_policy_hnd(&sam_pol)) {
1051 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1053 if (is_valid_policy_hnd(&domain_pol)) {
1054 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1056 if (is_valid_policy_hnd(&user_pol)) {
1057 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1059 TALLOC_FREE(pipe_hnd);
1061 return status;
1064 /****************************************************************
1065 ****************************************************************/
1067 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
1068 const char *machine_name,
1069 const char *dc_name)
1071 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
1072 struct cli_state *cli = NULL;
1073 struct rpc_pipe_client *pipe_hnd = NULL;
1074 struct rpc_pipe_client *netlogon_pipe = NULL;
1075 NTSTATUS status;
1076 char *machine_password = NULL;
1077 char *machine_account = NULL;
1079 if (!dc_name) {
1080 return NT_STATUS_INVALID_PARAMETER;
1083 if (!secrets_init()) {
1084 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1087 machine_password = secrets_fetch_machine_password(netbios_domain_name,
1088 NULL, NULL);
1089 if (!machine_password) {
1090 return NT_STATUS_NO_TRUST_LSA_SECRET;
1093 if (asprintf(&machine_account, "%s$", machine_name) == -1) {
1094 SAFE_FREE(machine_password);
1095 return NT_STATUS_NO_MEMORY;
1098 status = cli_full_connection(&cli, NULL,
1099 dc_name,
1100 NULL, 0,
1101 "IPC$", "IPC",
1102 machine_account,
1103 NULL,
1104 machine_password,
1106 Undefined, NULL);
1107 free(machine_account);
1108 free(machine_password);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 status = cli_full_connection(&cli, NULL,
1112 dc_name,
1113 NULL, 0,
1114 "IPC$", "IPC",
1116 NULL,
1119 Undefined, NULL);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 return status;
1126 status = get_schannel_session_key(cli, netbios_domain_name,
1127 &neg_flags, &netlogon_pipe);
1128 if (!NT_STATUS_IS_OK(status)) {
1129 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
1130 cli_shutdown(cli);
1131 return NT_STATUS_OK;
1134 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1135 "key from server %s for domain %s. Error was %s\n",
1136 cli->desthost, netbios_domain_name, nt_errstr(status)));
1137 cli_shutdown(cli);
1138 return status;
1141 if (!lp_client_schannel()) {
1142 cli_shutdown(cli);
1143 return NT_STATUS_OK;
1146 status = cli_rpc_pipe_open_schannel_with_key(
1147 cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
1148 DCERPC_AUTH_LEVEL_PRIVACY,
1149 netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd);
1151 cli_shutdown(cli);
1153 if (!NT_STATUS_IS_OK(status)) {
1154 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1155 "on netlogon pipe to server %s for domain %s. "
1156 "Error was %s\n",
1157 cli->desthost, netbios_domain_name, nt_errstr(status)));
1158 return status;
1161 return NT_STATUS_OK;
1164 /****************************************************************
1165 ****************************************************************/
1167 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1168 struct libnet_JoinCtx *r)
1170 NTSTATUS status;
1172 status = libnet_join_ok(r->out.netbios_domain_name,
1173 r->in.machine_name,
1174 r->in.dc_name);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 libnet_join_set_error_string(mem_ctx, r,
1177 "failed to verify domain membership after joining: %s",
1178 get_friendly_nt_error_msg(status));
1179 return WERR_SETUP_NOT_JOINED;
1182 return WERR_OK;
1185 /****************************************************************
1186 ****************************************************************/
1188 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1189 struct libnet_UnjoinCtx *r)
1191 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1192 return false;
1195 if (!secrets_delete_domain_sid(lp_workgroup())) {
1196 return false;
1199 return true;
1202 /****************************************************************
1203 ****************************************************************/
1205 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1206 struct libnet_UnjoinCtx *r)
1208 struct cli_state *cli = NULL;
1209 struct rpc_pipe_client *pipe_hnd = NULL;
1210 struct policy_handle sam_pol, domain_pol, user_pol;
1211 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1212 char *acct_name;
1213 uint32_t user_rid;
1214 struct lsa_String lsa_acct_name;
1215 struct samr_Ids user_rids;
1216 struct samr_Ids name_types;
1217 union samr_UserInfo *info = NULL;
1219 ZERO_STRUCT(sam_pol);
1220 ZERO_STRUCT(domain_pol);
1221 ZERO_STRUCT(user_pol);
1223 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1224 r->in.admin_account,
1225 r->in.admin_password,
1226 r->in.use_kerberos,
1227 &cli);
1228 if (!NT_STATUS_IS_OK(status)) {
1229 goto done;
1232 /* Open the domain */
1234 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
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;
1242 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1243 pipe_hnd->desthost,
1244 SEC_FLAG_MAXIMUM_ALLOWED,
1245 &sam_pol);
1246 if (!NT_STATUS_IS_OK(status)) {
1247 goto done;
1250 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1251 &sam_pol,
1252 SEC_FLAG_MAXIMUM_ALLOWED,
1253 r->in.domain_sid,
1254 &domain_pol);
1255 if (!NT_STATUS_IS_OK(status)) {
1256 goto done;
1259 /* Create domain user */
1261 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1262 strlower_m(acct_name);
1264 init_lsa_String(&lsa_acct_name, acct_name);
1266 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1267 &domain_pol,
1269 &lsa_acct_name,
1270 &user_rids,
1271 &name_types);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 goto done;
1277 if (name_types.ids[0] != SID_NAME_USER) {
1278 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1279 name_types.ids[0]));
1280 status = NT_STATUS_INVALID_WORKSTATION;
1281 goto done;
1284 user_rid = user_rids.ids[0];
1286 /* Open handle on user */
1288 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1289 &domain_pol,
1290 SEC_FLAG_MAXIMUM_ALLOWED,
1291 user_rid,
1292 &user_pol);
1293 if (!NT_STATUS_IS_OK(status)) {
1294 goto done;
1297 /* Get user info */
1299 status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1300 &user_pol,
1302 &info);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1305 goto done;
1308 /* now disable and setuser info */
1310 info->info16.acct_flags |= ACB_DISABLED;
1312 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1313 &user_pol,
1315 info);
1317 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1319 done:
1320 if (pipe_hnd) {
1321 if (is_valid_policy_hnd(&domain_pol)) {
1322 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1324 if (is_valid_policy_hnd(&sam_pol)) {
1325 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1327 TALLOC_FREE(pipe_hnd);
1330 if (cli) {
1331 cli_shutdown(cli);
1334 return status;
1337 /****************************************************************
1338 ****************************************************************/
1340 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1342 WERROR werr;
1343 struct smbconf_ctx *ctx;
1345 werr = smbconf_init_reg(r, &ctx, NULL);
1346 if (!W_ERROR_IS_OK(werr)) {
1347 goto done;
1350 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1352 werr = smbconf_set_global_parameter(ctx, "security", "user");
1353 W_ERROR_NOT_OK_GOTO_DONE(werr);
1355 werr = smbconf_set_global_parameter(ctx, "workgroup",
1356 r->in.domain_name);
1358 smbconf_delete_global_parameter(ctx, "realm");
1359 goto done;
1362 werr = smbconf_set_global_parameter(ctx, "security", "domain");
1363 W_ERROR_NOT_OK_GOTO_DONE(werr);
1365 werr = smbconf_set_global_parameter(ctx, "workgroup",
1366 r->out.netbios_domain_name);
1367 W_ERROR_NOT_OK_GOTO_DONE(werr);
1369 if (r->out.domain_is_ad) {
1370 werr = smbconf_set_global_parameter(ctx, "security", "ads");
1371 W_ERROR_NOT_OK_GOTO_DONE(werr);
1373 werr = smbconf_set_global_parameter(ctx, "realm",
1374 r->out.dns_domain_name);
1375 W_ERROR_NOT_OK_GOTO_DONE(werr);
1378 done:
1379 smbconf_shutdown(ctx);
1380 return werr;
1383 /****************************************************************
1384 ****************************************************************/
1386 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1388 WERROR werr = WERR_OK;
1389 struct smbconf_ctx *ctx;
1391 werr = smbconf_init_reg(r, &ctx, NULL);
1392 if (!W_ERROR_IS_OK(werr)) {
1393 goto done;
1396 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1398 werr = smbconf_set_global_parameter(ctx, "security", "user");
1399 W_ERROR_NOT_OK_GOTO_DONE(werr);
1401 werr = smbconf_delete_global_parameter(ctx, "workgroup");
1402 W_ERROR_NOT_OK_GOTO_DONE(werr);
1404 smbconf_delete_global_parameter(ctx, "realm");
1407 done:
1408 smbconf_shutdown(ctx);
1409 return werr;
1412 /****************************************************************
1413 ****************************************************************/
1415 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1417 WERROR werr;
1419 if (!W_ERROR_IS_OK(r->out.result)) {
1420 return r->out.result;
1423 if (!r->in.modify_config) {
1424 return WERR_OK;
1427 werr = do_join_modify_vals_config(r);
1428 if (!W_ERROR_IS_OK(werr)) {
1429 return werr;
1432 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1434 r->out.modified_config = true;
1435 r->out.result = werr;
1437 return werr;
1440 /****************************************************************
1441 ****************************************************************/
1443 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1445 WERROR werr;
1447 if (!W_ERROR_IS_OK(r->out.result)) {
1448 return r->out.result;
1451 if (!r->in.modify_config) {
1452 return WERR_OK;
1455 werr = do_unjoin_modify_vals_config(r);
1456 if (!W_ERROR_IS_OK(werr)) {
1457 return werr;
1460 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1462 r->out.modified_config = true;
1463 r->out.result = werr;
1465 return werr;
1468 /****************************************************************
1469 ****************************************************************/
1471 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1472 const char *domain_str,
1473 const char **domain_p,
1474 const char **dc_p)
1476 char *domain = NULL;
1477 char *dc = NULL;
1478 const char *p = NULL;
1480 if (!domain_str || !domain_p || !dc_p) {
1481 return false;
1484 p = strchr_m(domain_str, '\\');
1486 if (p != NULL) {
1487 domain = talloc_strndup(mem_ctx, domain_str,
1488 PTR_DIFF(p, domain_str));
1489 dc = talloc_strdup(mem_ctx, p+1);
1490 if (!dc) {
1491 return false;
1493 } else {
1494 domain = talloc_strdup(mem_ctx, domain_str);
1495 dc = NULL;
1497 if (!domain) {
1498 return false;
1501 *domain_p = domain;
1503 if (!*dc_p && dc) {
1504 *dc_p = dc;
1507 return true;
1510 /****************************************************************
1511 ****************************************************************/
1513 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1514 struct libnet_JoinCtx *r)
1516 if (!r->in.domain_name) {
1517 libnet_join_set_error_string(mem_ctx, r,
1518 "No domain name defined");
1519 return WERR_INVALID_PARAM;
1522 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1523 &r->in.domain_name,
1524 &r->in.dc_name)) {
1525 libnet_join_set_error_string(mem_ctx, r,
1526 "Failed to parse domain name");
1527 return WERR_INVALID_PARAM;
1530 if (IS_DC) {
1531 return WERR_SETUP_DOMAIN_CONTROLLER;
1534 if (!secrets_init()) {
1535 libnet_join_set_error_string(mem_ctx, r,
1536 "Unable to open secrets database");
1537 return WERR_CAN_NOT_COMPLETE;
1540 return WERR_OK;
1543 /****************************************************************
1544 ****************************************************************/
1546 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1548 NTSTATUS status;
1550 /* Try adding dom admins to builtin\admins. Only log failures. */
1551 status = create_builtin_administrators(domain_sid);
1552 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1553 DEBUG(10,("Unable to auto-add domain administrators to "
1554 "BUILTIN\\Administrators during join because "
1555 "winbindd must be running."));
1556 } else if (!NT_STATUS_IS_OK(status)) {
1557 DEBUG(5, ("Failed to auto-add domain administrators to "
1558 "BUILTIN\\Administrators during join: %s\n",
1559 nt_errstr(status)));
1562 /* Try adding dom users to builtin\users. Only log failures. */
1563 status = create_builtin_users(domain_sid);
1564 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1565 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1566 "during join because winbindd must be running."));
1567 } else if (!NT_STATUS_IS_OK(status)) {
1568 DEBUG(5, ("Failed to auto-add domain administrators to "
1569 "BUILTIN\\Administrators during join: %s\n",
1570 nt_errstr(status)));
1574 /****************************************************************
1575 ****************************************************************/
1577 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1578 struct libnet_JoinCtx *r)
1580 WERROR werr;
1582 if (!W_ERROR_IS_OK(r->out.result)) {
1583 return r->out.result;
1586 werr = do_JoinConfig(r);
1587 if (!W_ERROR_IS_OK(werr)) {
1588 return werr;
1591 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1592 return WERR_OK;
1595 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1596 if (r->out.dns_domain_name) {
1597 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1600 #ifdef WITH_ADS
1601 if (r->out.domain_is_ad &&
1602 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1603 ADS_STATUS ads_status;
1605 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1606 if (!ADS_ERR_OK(ads_status)) {
1607 return WERR_GENERAL_FAILURE;
1610 #endif /* WITH_ADS */
1612 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1614 return WERR_OK;
1617 /****************************************************************
1618 ****************************************************************/
1620 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1622 const char *krb5_cc_env = NULL;
1624 if (r->in.ads) {
1625 ads_destroy(&r->in.ads);
1628 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1629 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1630 unsetenv(KRB5_ENV_CCNAME);
1633 return 0;
1636 /****************************************************************
1637 ****************************************************************/
1639 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1641 const char *krb5_cc_env = NULL;
1643 if (r->in.ads) {
1644 ads_destroy(&r->in.ads);
1647 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1648 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1649 unsetenv(KRB5_ENV_CCNAME);
1652 return 0;
1655 /****************************************************************
1656 ****************************************************************/
1658 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1659 struct libnet_JoinCtx **r)
1661 struct libnet_JoinCtx *ctx;
1662 const char *krb5_cc_env = NULL;
1664 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1665 if (!ctx) {
1666 return WERR_NOMEM;
1669 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1671 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1672 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1674 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1675 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1676 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1677 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1678 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1681 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1683 *r = ctx;
1685 return WERR_OK;
1688 /****************************************************************
1689 ****************************************************************/
1691 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1692 struct libnet_UnjoinCtx **r)
1694 struct libnet_UnjoinCtx *ctx;
1695 const char *krb5_cc_env = NULL;
1697 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1698 if (!ctx) {
1699 return WERR_NOMEM;
1702 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1704 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1705 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1707 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1708 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1709 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1710 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1711 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1714 *r = ctx;
1716 return WERR_OK;
1719 /****************************************************************
1720 ****************************************************************/
1722 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
1723 struct libnet_JoinCtx *r)
1725 bool valid_security = false;
1726 bool valid_workgroup = false;
1727 bool valid_realm = false;
1729 /* check if configuration is already set correctly */
1731 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
1733 switch (r->out.domain_is_ad) {
1734 case false:
1735 valid_security = (lp_security() == SEC_DOMAIN);
1736 if (valid_workgroup && valid_security) {
1737 /* nothing to be done */
1738 return WERR_OK;
1740 break;
1741 case true:
1742 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
1743 switch (lp_security()) {
1744 case SEC_DOMAIN:
1745 case SEC_ADS:
1746 valid_security = true;
1749 if (valid_workgroup && valid_realm && valid_security) {
1750 /* nothing to be done */
1751 return WERR_OK;
1753 break;
1756 /* check if we are supposed to manipulate configuration */
1758 if (!r->in.modify_config) {
1760 char *wrong_conf = talloc_strdup(mem_ctx, "");
1762 if (!valid_workgroup) {
1763 wrong_conf = talloc_asprintf_append(wrong_conf,
1764 "\"workgroup\" set to '%s', should be '%s'",
1765 lp_workgroup(), r->out.netbios_domain_name);
1766 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1769 if (!valid_realm) {
1770 wrong_conf = talloc_asprintf_append(wrong_conf,
1771 "\"realm\" set to '%s', should be '%s'",
1772 lp_realm(), r->out.dns_domain_name);
1773 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1776 if (!valid_security) {
1777 const char *sec = NULL;
1778 switch (lp_security()) {
1779 case SEC_SHARE: sec = "share"; break;
1780 case SEC_USER: sec = "user"; break;
1781 case SEC_DOMAIN: sec = "domain"; break;
1782 case SEC_ADS: sec = "ads"; break;
1784 wrong_conf = talloc_asprintf_append(wrong_conf,
1785 "\"security\" set to '%s', should be %s",
1786 sec, r->out.domain_is_ad ?
1787 "either 'domain' or 'ads'" : "'domain'");
1788 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1791 libnet_join_set_error_string(mem_ctx, r,
1792 "Invalid configuration (%s) and configuration modification "
1793 "was not requested", wrong_conf);
1794 return WERR_CAN_NOT_COMPLETE;
1797 /* check if we are able to manipulate configuration */
1799 if (!lp_config_backend_is_registry()) {
1800 libnet_join_set_error_string(mem_ctx, r,
1801 "Configuration manipulation requested but not "
1802 "supported by backend");
1803 return WERR_NOT_SUPPORTED;
1806 return WERR_OK;
1809 /****************************************************************
1810 ****************************************************************/
1812 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1813 struct libnet_JoinCtx *r)
1815 NTSTATUS status;
1816 WERROR werr;
1817 struct cli_state *cli = NULL;
1818 #ifdef WITH_ADS
1819 ADS_STATUS ads_status;
1820 #endif /* WITH_ADS */
1822 if (!r->in.dc_name) {
1823 struct netr_DsRGetDCNameInfo *info;
1824 const char *dc;
1825 status = dsgetdcname(mem_ctx,
1826 r->in.msg_ctx,
1827 r->in.domain_name,
1828 NULL,
1829 NULL,
1830 DS_FORCE_REDISCOVERY |
1831 DS_DIRECTORY_SERVICE_REQUIRED |
1832 DS_WRITABLE_REQUIRED |
1833 DS_RETURN_DNS_NAME,
1834 &info);
1835 if (!NT_STATUS_IS_OK(status)) {
1836 libnet_join_set_error_string(mem_ctx, r,
1837 "failed to find DC for domain %s",
1838 r->in.domain_name,
1839 get_friendly_nt_error_msg(status));
1840 return WERR_DCNOTFOUND;
1843 dc = strip_hostname(info->dc_unc);
1844 r->in.dc_name = talloc_strdup(mem_ctx, dc);
1845 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1848 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
1849 if (!NT_STATUS_IS_OK(status)) {
1850 libnet_join_set_error_string(mem_ctx, r,
1851 "failed to lookup DC info for domain '%s' over rpc: %s",
1852 r->in.domain_name, get_friendly_nt_error_msg(status));
1853 return ntstatus_to_werror(status);
1856 werr = libnet_join_check_config(mem_ctx, r);
1857 if (!W_ERROR_IS_OK(werr)) {
1858 goto done;
1861 #ifdef WITH_ADS
1862 if (r->out.domain_is_ad && r->in.account_ou &&
1863 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1865 ads_status = libnet_join_connect_ads(mem_ctx, r);
1866 if (!ADS_ERR_OK(ads_status)) {
1867 return WERR_DEFAULT_JOIN_REQUIRED;
1870 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1871 if (!ADS_ERR_OK(ads_status)) {
1872 libnet_join_set_error_string(mem_ctx, r,
1873 "failed to precreate account in ou %s: %s",
1874 r->in.account_ou,
1875 ads_errstr(ads_status));
1876 return WERR_DEFAULT_JOIN_REQUIRED;
1879 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1881 #endif /* WITH_ADS */
1883 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
1884 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
1885 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
1886 } else {
1887 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
1889 if (!NT_STATUS_IS_OK(status)) {
1890 libnet_join_set_error_string(mem_ctx, r,
1891 "failed to join domain '%s' over rpc: %s",
1892 r->in.domain_name, get_friendly_nt_error_msg(status));
1893 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1894 return WERR_SETUP_ALREADY_JOINED;
1896 werr = ntstatus_to_werror(status);
1897 goto done;
1900 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1901 werr = WERR_SETUP_NOT_JOINED;
1902 goto done;
1905 werr = WERR_OK;
1907 done:
1908 if (cli) {
1909 cli_shutdown(cli);
1912 return werr;
1915 /****************************************************************
1916 ****************************************************************/
1918 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
1919 struct libnet_JoinCtx *r)
1921 WERROR werr;
1922 struct libnet_UnjoinCtx *u = NULL;
1924 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
1925 if (!W_ERROR_IS_OK(werr)) {
1926 return werr;
1929 u->in.debug = r->in.debug;
1930 u->in.dc_name = r->in.dc_name;
1931 u->in.domain_name = r->in.domain_name;
1932 u->in.admin_account = r->in.admin_account;
1933 u->in.admin_password = r->in.admin_password;
1934 u->in.modify_config = r->in.modify_config;
1935 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1936 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1938 werr = libnet_Unjoin(mem_ctx, u);
1939 TALLOC_FREE(u);
1941 return werr;
1944 /****************************************************************
1945 ****************************************************************/
1947 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1948 struct libnet_JoinCtx *r)
1950 WERROR werr;
1952 if (r->in.debug) {
1953 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
1956 werr = libnet_join_pre_processing(mem_ctx, r);
1957 if (!W_ERROR_IS_OK(werr)) {
1958 goto done;
1961 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1962 werr = libnet_DomainJoin(mem_ctx, r);
1963 if (!W_ERROR_IS_OK(werr)) {
1964 goto done;
1968 werr = libnet_join_post_processing(mem_ctx, r);
1969 if (!W_ERROR_IS_OK(werr)) {
1970 goto done;
1973 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1974 werr = libnet_join_post_verify(mem_ctx, r);
1975 if (!W_ERROR_IS_OK(werr)) {
1976 libnet_join_rollback(mem_ctx, r);
1980 done:
1981 r->out.result = werr;
1983 if (r->in.debug) {
1984 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
1986 return werr;
1989 /****************************************************************
1990 ****************************************************************/
1992 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1993 struct libnet_UnjoinCtx *r)
1995 NTSTATUS status;
1997 if (!r->in.domain_sid) {
1998 struct dom_sid sid;
1999 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2000 libnet_unjoin_set_error_string(mem_ctx, r,
2001 "Unable to fetch domain sid: are we joined?");
2002 return WERR_SETUP_NOT_JOINED;
2004 r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid);
2005 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2008 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2009 !r->in.delete_machine_account) {
2010 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2011 return WERR_OK;
2014 if (!r->in.dc_name) {
2015 struct netr_DsRGetDCNameInfo *info;
2016 const char *dc;
2017 status = dsgetdcname(mem_ctx,
2018 r->in.msg_ctx,
2019 r->in.domain_name,
2020 NULL,
2021 NULL,
2022 DS_DIRECTORY_SERVICE_REQUIRED |
2023 DS_WRITABLE_REQUIRED |
2024 DS_RETURN_DNS_NAME,
2025 &info);
2026 if (!NT_STATUS_IS_OK(status)) {
2027 libnet_unjoin_set_error_string(mem_ctx, r,
2028 "failed to find DC for domain %s",
2029 r->in.domain_name,
2030 get_friendly_nt_error_msg(status));
2031 return WERR_DCNOTFOUND;
2034 dc = strip_hostname(info->dc_unc);
2035 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2036 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2039 #ifdef WITH_ADS
2040 /* for net ads leave, try to delete the account. If it works,
2041 no sense in disabling. If it fails, we can still try to
2042 disable it. jmcd */
2044 if (r->in.delete_machine_account) {
2045 ADS_STATUS ads_status;
2046 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2047 if (ADS_ERR_OK(ads_status)) {
2048 /* dirty hack */
2049 r->out.dns_domain_name =
2050 talloc_strdup(mem_ctx,
2051 r->in.ads->server.realm);
2052 ads_status =
2053 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2055 if (!ADS_ERR_OK(ads_status)) {
2056 libnet_unjoin_set_error_string(mem_ctx, r,
2057 "failed to remove machine account from AD: %s",
2058 ads_errstr(ads_status));
2059 } else {
2060 r->out.deleted_machine_account = true;
2061 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2062 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2063 return WERR_OK;
2066 #endif /* WITH_ADS */
2068 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2069 "disable". */
2070 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2071 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2072 if (!NT_STATUS_IS_OK(status)) {
2073 libnet_unjoin_set_error_string(mem_ctx, r,
2074 "failed to disable machine account via rpc: %s",
2075 get_friendly_nt_error_msg(status));
2076 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2077 return WERR_SETUP_NOT_JOINED;
2079 return ntstatus_to_werror(status);
2082 r->out.disabled_machine_account = true;
2085 /* If disable succeeded or was not requested at all, we
2086 should be getting rid of our end of things */
2088 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2090 return WERR_OK;
2093 /****************************************************************
2094 ****************************************************************/
2096 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2097 struct libnet_UnjoinCtx *r)
2099 if (!r->in.domain_name) {
2100 libnet_unjoin_set_error_string(mem_ctx, r,
2101 "No domain name defined");
2102 return WERR_INVALID_PARAM;
2105 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2106 &r->in.domain_name,
2107 &r->in.dc_name)) {
2108 libnet_unjoin_set_error_string(mem_ctx, r,
2109 "Failed to parse domain name");
2110 return WERR_INVALID_PARAM;
2113 if (IS_DC) {
2114 return WERR_SETUP_DOMAIN_CONTROLLER;
2117 if (!secrets_init()) {
2118 libnet_unjoin_set_error_string(mem_ctx, r,
2119 "Unable to open secrets database");
2120 return WERR_CAN_NOT_COMPLETE;
2123 return WERR_OK;
2126 /****************************************************************
2127 ****************************************************************/
2129 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2130 struct libnet_UnjoinCtx *r)
2132 saf_delete(r->out.netbios_domain_name);
2133 saf_delete(r->out.dns_domain_name);
2135 return libnet_unjoin_config(r);
2138 /****************************************************************
2139 ****************************************************************/
2141 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2142 struct libnet_UnjoinCtx *r)
2144 WERROR werr;
2146 if (r->in.debug) {
2147 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2150 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2151 if (!W_ERROR_IS_OK(werr)) {
2152 goto done;
2155 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2156 werr = libnet_DomainUnjoin(mem_ctx, r);
2157 if (!W_ERROR_IS_OK(werr)) {
2158 libnet_unjoin_config(r);
2159 goto done;
2163 werr = libnet_unjoin_post_processing(mem_ctx, r);
2164 if (!W_ERROR_IS_OK(werr)) {
2165 goto done;
2168 done:
2169 r->out.result = werr;
2171 if (r->in.debug) {
2172 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2175 return werr;