s3:net factor out net_idmap_dbfile
[Samba.git] / source3 / libnet / libnet_join.c
blob6c8560887f22179fa2899b5cb7245a3bfaea59da
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 "krb5_env.h"
38 #include "../libcli/security/security.h"
40 /****************************************************************
41 ****************************************************************/
43 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
44 do { \
45 char *str = NULL; \
46 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
47 DEBUG(1,("libnet_Join:\n%s", str)); \
48 TALLOC_FREE(str); \
49 } while (0)
51 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
52 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
53 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
54 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
56 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
57 do { \
58 char *str = NULL; \
59 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
60 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
61 TALLOC_FREE(str); \
62 } while (0)
64 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
65 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
66 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
67 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
69 /****************************************************************
70 ****************************************************************/
72 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
73 struct libnet_JoinCtx *r,
74 const char *format, ...)
76 va_list args;
78 if (r->out.error_string) {
79 return;
82 va_start(args, format);
83 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
84 va_end(args);
87 /****************************************************************
88 ****************************************************************/
90 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
91 struct libnet_UnjoinCtx *r,
92 const char *format, ...)
94 va_list args;
96 if (r->out.error_string) {
97 return;
100 va_start(args, format);
101 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
102 va_end(args);
105 #ifdef WITH_ADS
107 /****************************************************************
108 ****************************************************************/
110 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
111 const char *netbios_domain_name,
112 const char *dc_name,
113 const char *user_name,
114 const char *password,
115 ADS_STRUCT **ads)
117 ADS_STATUS status;
118 ADS_STRUCT *my_ads = NULL;
119 char *cp;
121 my_ads = ads_init(dns_domain_name,
122 netbios_domain_name,
123 dc_name);
124 if (!my_ads) {
125 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
128 if (user_name) {
129 SAFE_FREE(my_ads->auth.user_name);
130 my_ads->auth.user_name = SMB_STRDUP(user_name);
131 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
132 *cp++ = '\0';
133 SAFE_FREE(my_ads->auth.realm);
134 my_ads->auth.realm = smb_xstrdup(cp);
135 strupper_m(my_ads->auth.realm);
139 if (password) {
140 SAFE_FREE(my_ads->auth.password);
141 my_ads->auth.password = SMB_STRDUP(password);
144 status = ads_connect_user_creds(my_ads);
145 if (!ADS_ERR_OK(status)) {
146 ads_destroy(&my_ads);
147 return status;
150 *ads = my_ads;
151 return ADS_SUCCESS;
154 /****************************************************************
155 ****************************************************************/
157 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
158 struct libnet_JoinCtx *r)
160 ADS_STATUS status;
162 status = libnet_connect_ads(r->out.dns_domain_name,
163 r->out.netbios_domain_name,
164 r->in.dc_name,
165 r->in.admin_account,
166 r->in.admin_password,
167 &r->in.ads);
168 if (!ADS_ERR_OK(status)) {
169 libnet_join_set_error_string(mem_ctx, r,
170 "failed to connect to AD: %s",
171 ads_errstr(status));
172 return status;
175 if (!r->out.netbios_domain_name) {
176 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
177 r->in.ads->server.workgroup);
178 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
181 if (!r->out.dns_domain_name) {
182 r->out.dns_domain_name = talloc_strdup(mem_ctx,
183 r->in.ads->config.realm);
184 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
187 r->out.domain_is_ad = true;
189 return ADS_SUCCESS;
192 /****************************************************************
193 ****************************************************************/
195 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
196 struct libnet_UnjoinCtx *r)
198 ADS_STATUS status;
200 status = libnet_connect_ads(r->in.domain_name,
201 r->in.domain_name,
202 r->in.dc_name,
203 r->in.admin_account,
204 r->in.admin_password,
205 &r->in.ads);
206 if (!ADS_ERR_OK(status)) {
207 libnet_unjoin_set_error_string(mem_ctx, r,
208 "failed to connect to AD: %s",
209 ads_errstr(status));
212 return status;
215 /****************************************************************
216 join a domain using ADS (LDAP mods)
217 ****************************************************************/
219 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
220 struct libnet_JoinCtx *r)
222 ADS_STATUS status;
223 LDAPMessage *res = NULL;
224 const char *attrs[] = { "dn", NULL };
225 bool moved = false;
227 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
228 if (!ADS_ERR_OK(status)) {
229 return status;
232 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
233 if (!ADS_ERR_OK(status)) {
234 return status;
237 if (ads_count_replies(r->in.ads, res) != 1) {
238 ads_msgfree(r->in.ads, res);
239 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
242 ads_msgfree(r->in.ads, res);
244 /* Attempt to create the machine account and bail if this fails.
245 Assume that the admin wants exactly what they requested */
247 status = ads_create_machine_acct(r->in.ads,
248 r->in.machine_name,
249 r->in.account_ou);
251 if (ADS_ERR_OK(status)) {
252 DEBUG(1,("machine account creation created\n"));
253 return status;
254 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
255 (status.err.rc == LDAP_ALREADY_EXISTS)) {
256 status = ADS_SUCCESS;
259 if (!ADS_ERR_OK(status)) {
260 DEBUG(1,("machine account creation failed\n"));
261 return status;
264 status = ads_move_machine_acct(r->in.ads,
265 r->in.machine_name,
266 r->in.account_ou,
267 &moved);
268 if (!ADS_ERR_OK(status)) {
269 DEBUG(1,("failure to locate/move pre-existing "
270 "machine account\n"));
271 return status;
274 DEBUG(1,("The machine account %s the specified OU.\n",
275 moved ? "was moved into" : "already exists in"));
277 return status;
280 /****************************************************************
281 ****************************************************************/
283 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
284 struct libnet_UnjoinCtx *r)
286 ADS_STATUS status;
288 if (!r->in.ads) {
289 status = libnet_unjoin_connect_ads(mem_ctx, r);
290 if (!ADS_ERR_OK(status)) {
291 libnet_unjoin_set_error_string(mem_ctx, r,
292 "failed to connect to AD: %s",
293 ads_errstr(status));
294 return status;
298 status = ads_leave_realm(r->in.ads, r->in.machine_name);
299 if (!ADS_ERR_OK(status)) {
300 libnet_unjoin_set_error_string(mem_ctx, r,
301 "failed to leave realm: %s",
302 ads_errstr(status));
303 return status;
306 return ADS_SUCCESS;
309 /****************************************************************
310 ****************************************************************/
312 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
313 struct libnet_JoinCtx *r)
315 ADS_STATUS status;
316 LDAPMessage *res = NULL;
317 char *dn = NULL;
319 if (!r->in.machine_name) {
320 return ADS_ERROR(LDAP_NO_MEMORY);
323 status = ads_find_machine_acct(r->in.ads,
324 &res,
325 r->in.machine_name);
326 if (!ADS_ERR_OK(status)) {
327 return status;
330 if (ads_count_replies(r->in.ads, res) != 1) {
331 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
332 goto done;
335 dn = ads_get_dn(r->in.ads, mem_ctx, res);
336 if (!dn) {
337 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
338 goto done;
341 r->out.dn = talloc_strdup(mem_ctx, dn);
342 if (!r->out.dn) {
343 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
344 goto done;
347 done:
348 ads_msgfree(r->in.ads, res);
349 TALLOC_FREE(dn);
351 return status;
354 /****************************************************************
355 Set a machines dNSHostName and servicePrincipalName attributes
356 ****************************************************************/
358 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
359 struct libnet_JoinCtx *r)
361 ADS_STATUS status;
362 ADS_MODLIST mods;
363 fstring my_fqdn;
364 const char *spn_array[3] = {NULL, NULL, NULL};
365 char *spn = NULL;
367 /* Find our DN */
369 status = libnet_join_find_machine_acct(mem_ctx, r);
370 if (!ADS_ERR_OK(status)) {
371 return status;
374 /* Windows only creates HOST/shortname & HOST/fqdn. */
376 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
377 if (!spn) {
378 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
380 strupper_m(spn);
381 spn_array[0] = spn;
383 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
384 || (strchr(my_fqdn, '.') == NULL)) {
385 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
386 r->out.dns_domain_name);
389 strlower_m(my_fqdn);
391 if (!strequal(my_fqdn, r->in.machine_name)) {
392 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
393 if (!spn) {
394 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
396 spn_array[1] = spn;
399 mods = ads_init_mods(mem_ctx);
400 if (!mods) {
401 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
404 /* fields of primary importance */
406 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
407 if (!ADS_ERR_OK(status)) {
408 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
411 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
412 spn_array);
413 if (!ADS_ERR_OK(status)) {
414 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
417 return ads_gen_mod(r->in.ads, r->out.dn, mods);
420 /****************************************************************
421 ****************************************************************/
423 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
424 struct libnet_JoinCtx *r)
426 ADS_STATUS status;
427 ADS_MODLIST mods;
429 if (!r->in.create_upn) {
430 return ADS_SUCCESS;
433 /* Find our DN */
435 status = libnet_join_find_machine_acct(mem_ctx, r);
436 if (!ADS_ERR_OK(status)) {
437 return status;
440 if (!r->in.upn) {
441 r->in.upn = talloc_asprintf(mem_ctx,
442 "host/%s@%s",
443 r->in.machine_name,
444 r->out.dns_domain_name);
445 if (!r->in.upn) {
446 return ADS_ERROR(LDAP_NO_MEMORY);
450 /* now do the mods */
452 mods = ads_init_mods(mem_ctx);
453 if (!mods) {
454 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
457 /* fields of primary importance */
459 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
460 if (!ADS_ERR_OK(status)) {
461 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
464 return ads_gen_mod(r->in.ads, r->out.dn, mods);
468 /****************************************************************
469 ****************************************************************/
471 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
472 struct libnet_JoinCtx *r)
474 ADS_STATUS status;
475 ADS_MODLIST mods;
476 char *os_sp = NULL;
478 if (!r->in.os_name || !r->in.os_version ) {
479 return ADS_SUCCESS;
482 /* Find our DN */
484 status = libnet_join_find_machine_acct(mem_ctx, r);
485 if (!ADS_ERR_OK(status)) {
486 return status;
489 /* now do the mods */
491 mods = ads_init_mods(mem_ctx);
492 if (!mods) {
493 return ADS_ERROR(LDAP_NO_MEMORY);
496 os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
497 if (!os_sp) {
498 return ADS_ERROR(LDAP_NO_MEMORY);
501 /* fields of primary importance */
503 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
504 r->in.os_name);
505 if (!ADS_ERR_OK(status)) {
506 return status;
509 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
510 r->in.os_version);
511 if (!ADS_ERR_OK(status)) {
512 return status;
515 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
516 os_sp);
517 if (!ADS_ERR_OK(status)) {
518 return status;
521 return ads_gen_mod(r->in.ads, r->out.dn, mods);
524 /****************************************************************
525 ****************************************************************/
527 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
528 struct libnet_JoinCtx *r)
530 if (!USE_SYSTEM_KEYTAB) {
531 return true;
534 if (ads_keytab_create_default(r->in.ads) != 0) {
535 return false;
538 return true;
541 /****************************************************************
542 ****************************************************************/
544 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
545 struct libnet_JoinCtx *r)
547 uint32_t domain_func;
548 ADS_STATUS status;
549 const char *salt = NULL;
550 char *std_salt = NULL;
552 status = ads_domain_func_level(r->in.ads, &domain_func);
553 if (!ADS_ERR_OK(status)) {
554 libnet_join_set_error_string(mem_ctx, r,
555 "failed to determine domain functional level: %s",
556 ads_errstr(status));
557 return false;
560 /* go ahead and setup the default salt */
562 std_salt = kerberos_standard_des_salt();
563 if (!std_salt) {
564 libnet_join_set_error_string(mem_ctx, r,
565 "failed to obtain standard DES salt");
566 return false;
569 salt = talloc_strdup(mem_ctx, std_salt);
570 if (!salt) {
571 return false;
574 SAFE_FREE(std_salt);
576 /* if it's a Windows functional domain, we have to look for the UPN */
578 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
579 char *upn;
581 upn = ads_get_upn(r->in.ads, mem_ctx,
582 r->in.machine_name);
583 if (upn) {
584 salt = talloc_strdup(mem_ctx, upn);
585 if (!salt) {
586 return false;
591 return kerberos_secrets_store_des_salt(salt);
594 /****************************************************************
595 ****************************************************************/
597 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
598 struct libnet_JoinCtx *r)
600 ADS_STATUS status;
602 if (!r->in.ads) {
603 status = libnet_join_connect_ads(mem_ctx, r);
604 if (!ADS_ERR_OK(status)) {
605 return status;
609 status = libnet_join_set_machine_spn(mem_ctx, r);
610 if (!ADS_ERR_OK(status)) {
611 libnet_join_set_error_string(mem_ctx, r,
612 "failed to set machine spn: %s",
613 ads_errstr(status));
614 return status;
617 status = libnet_join_set_os_attributes(mem_ctx, r);
618 if (!ADS_ERR_OK(status)) {
619 libnet_join_set_error_string(mem_ctx, r,
620 "failed to set machine os attributes: %s",
621 ads_errstr(status));
622 return status;
625 status = libnet_join_set_machine_upn(mem_ctx, r);
626 if (!ADS_ERR_OK(status)) {
627 libnet_join_set_error_string(mem_ctx, r,
628 "failed to set machine upn: %s",
629 ads_errstr(status));
630 return status;
633 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
634 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
637 if (!libnet_join_create_keytab(mem_ctx, r)) {
638 libnet_join_set_error_string(mem_ctx, r,
639 "failed to create kerberos keytab");
640 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
643 return ADS_SUCCESS;
645 #endif /* WITH_ADS */
647 /****************************************************************
648 Store the machine password and domain SID
649 ****************************************************************/
651 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
652 struct libnet_JoinCtx *r)
654 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
655 r->out.domain_sid))
657 DEBUG(1,("Failed to save domain sid\n"));
658 return false;
661 if (!secrets_store_machine_password(r->in.machine_password,
662 r->out.netbios_domain_name,
663 r->in.secure_channel_type))
665 DEBUG(1,("Failed to save machine password\n"));
666 return false;
669 return true;
672 /****************************************************************
673 Connect dc's IPC$ share
674 ****************************************************************/
676 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
677 const char *user,
678 const char *pass,
679 bool use_kerberos,
680 struct cli_state **cli)
682 int flags = 0;
684 if (use_kerberos) {
685 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
688 if (use_kerberos && pass) {
689 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
692 return cli_full_connection(cli, NULL,
694 NULL, 0,
695 "IPC$", "IPC",
696 user,
697 NULL,
698 pass,
699 flags,
700 Undefined);
703 /****************************************************************
704 Lookup domain dc's info
705 ****************************************************************/
707 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
708 struct libnet_JoinCtx *r,
709 struct cli_state **cli)
711 struct rpc_pipe_client *pipe_hnd = NULL;
712 struct policy_handle lsa_pol;
713 NTSTATUS status, result;
714 union lsa_PolicyInformation *info = NULL;
715 struct dcerpc_binding_handle *b;
717 status = libnet_join_connect_dc_ipc(r->in.dc_name,
718 r->in.admin_account,
719 r->in.admin_password,
720 r->in.use_kerberos,
721 cli);
722 if (!NT_STATUS_IS_OK(status)) {
723 goto done;
726 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id,
727 &pipe_hnd);
728 if (!NT_STATUS_IS_OK(status)) {
729 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
730 nt_errstr(status)));
731 goto done;
734 b = pipe_hnd->binding_handle;
736 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
737 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
738 if (!NT_STATUS_IS_OK(status)) {
739 goto done;
742 status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
743 &lsa_pol,
744 LSA_POLICY_INFO_DNS,
745 &info,
746 &result);
747 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
748 r->out.domain_is_ad = true;
749 r->out.netbios_domain_name = info->dns.name.string;
750 r->out.dns_domain_name = info->dns.dns_domain.string;
751 r->out.forest_name = info->dns.dns_forest.string;
752 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
753 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
756 if (!NT_STATUS_IS_OK(status)) {
757 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
758 &lsa_pol,
759 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
760 &info,
761 &result);
762 if (!NT_STATUS_IS_OK(status)) {
763 goto done;
765 if (!NT_STATUS_IS_OK(result)) {
766 status = result;
767 goto done;
770 r->out.netbios_domain_name = info->account_domain.name.string;
771 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
772 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
775 dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
776 TALLOC_FREE(pipe_hnd);
778 done:
779 return status;
782 /****************************************************************
783 Do the domain join unsecure
784 ****************************************************************/
786 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
787 struct libnet_JoinCtx *r,
788 struct cli_state *cli)
790 struct rpc_pipe_client *pipe_hnd = NULL;
791 unsigned char orig_trust_passwd_hash[16];
792 unsigned char new_trust_passwd_hash[16];
793 fstring trust_passwd;
794 NTSTATUS status;
796 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
797 &pipe_hnd);
798 if (!NT_STATUS_IS_OK(status)) {
799 return status;
802 if (!r->in.machine_password) {
803 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
804 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
807 E_md4hash(r->in.machine_password, new_trust_passwd_hash);
809 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
810 fstrcpy(trust_passwd, r->in.admin_password);
811 strlower_m(trust_passwd);
814 * Machine names can be 15 characters, but the max length on
815 * a password is 14. --jerry
818 trust_passwd[14] = '\0';
820 E_md4hash(trust_passwd, orig_trust_passwd_hash);
822 status = rpccli_netlogon_set_trust_password(pipe_hnd, mem_ctx,
823 r->in.machine_name,
824 orig_trust_passwd_hash,
825 r->in.machine_password,
826 new_trust_passwd_hash,
827 r->in.secure_channel_type);
829 return status;
832 /****************************************************************
833 Do the domain join
834 ****************************************************************/
836 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
837 struct libnet_JoinCtx *r,
838 struct cli_state *cli)
840 struct rpc_pipe_client *pipe_hnd = NULL;
841 struct policy_handle sam_pol, domain_pol, user_pol;
842 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
843 char *acct_name;
844 struct lsa_String lsa_acct_name;
845 uint32_t user_rid;
846 uint32_t acct_flags = ACB_WSTRUST;
847 struct samr_Ids user_rids;
848 struct samr_Ids name_types;
849 union samr_UserInfo user_info;
850 struct dcerpc_binding_handle *b = NULL;
852 struct samr_CryptPassword crypt_pwd;
853 struct samr_CryptPasswordEx crypt_pwd_ex;
855 ZERO_STRUCT(sam_pol);
856 ZERO_STRUCT(domain_pol);
857 ZERO_STRUCT(user_pol);
859 switch (r->in.secure_channel_type) {
860 case SEC_CHAN_WKSTA:
861 acct_flags = ACB_WSTRUST;
862 break;
863 case SEC_CHAN_BDC:
864 acct_flags = ACB_SVRTRUST;
865 break;
866 default:
867 return NT_STATUS_INVALID_PARAMETER;
870 if (!r->in.machine_password) {
871 r->in.machine_password = generate_random_str(mem_ctx, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
872 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
875 /* Open the domain */
877 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
878 &pipe_hnd);
879 if (!NT_STATUS_IS_OK(status)) {
880 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
881 nt_errstr(status)));
882 goto done;
885 b = pipe_hnd->binding_handle;
887 status = dcerpc_samr_Connect2(b, mem_ctx,
888 pipe_hnd->desthost,
889 SAMR_ACCESS_ENUM_DOMAINS
890 | SAMR_ACCESS_LOOKUP_DOMAIN,
891 &sam_pol,
892 &result);
893 if (!NT_STATUS_IS_OK(status)) {
894 goto done;
896 if (!NT_STATUS_IS_OK(result)) {
897 status = result;
898 goto done;
901 status = dcerpc_samr_OpenDomain(b, mem_ctx,
902 &sam_pol,
903 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
904 | SAMR_DOMAIN_ACCESS_CREATE_USER
905 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
906 r->out.domain_sid,
907 &domain_pol,
908 &result);
909 if (!NT_STATUS_IS_OK(status)) {
910 goto done;
912 if (!NT_STATUS_IS_OK(result)) {
913 status = result;
914 goto done;
917 /* Create domain user */
919 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
920 strlower_m(acct_name);
922 init_lsa_String(&lsa_acct_name, acct_name);
924 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
925 uint32_t access_desired =
926 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
927 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
928 SAMR_USER_ACCESS_SET_PASSWORD |
929 SAMR_USER_ACCESS_GET_ATTRIBUTES |
930 SAMR_USER_ACCESS_SET_ATTRIBUTES;
931 uint32_t access_granted = 0;
933 DEBUG(10,("Creating account with desired access mask: %d\n",
934 access_desired));
936 status = dcerpc_samr_CreateUser2(b, mem_ctx,
937 &domain_pol,
938 &lsa_acct_name,
939 acct_flags,
940 access_desired,
941 &user_pol,
942 &access_granted,
943 &user_rid,
944 &result);
945 if (!NT_STATUS_IS_OK(status)) {
946 goto done;
949 status = result;
950 if (!NT_STATUS_IS_OK(status) &&
951 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
953 DEBUG(10,("Creation of workstation account failed: %s\n",
954 nt_errstr(status)));
956 /* If NT_STATUS_ACCESS_DENIED then we have a valid
957 username/password combo but the user does not have
958 administrator access. */
960 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
961 libnet_join_set_error_string(mem_ctx, r,
962 "User specified does not have "
963 "administrator privileges");
966 goto done;
969 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
970 if (!(r->in.join_flags &
971 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
972 goto done;
976 /* We *must* do this.... don't ask... */
978 if (NT_STATUS_IS_OK(status)) {
979 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
983 status = dcerpc_samr_LookupNames(b, mem_ctx,
984 &domain_pol,
986 &lsa_acct_name,
987 &user_rids,
988 &name_types,
989 &result);
990 if (!NT_STATUS_IS_OK(status)) {
991 goto done;
993 if (!NT_STATUS_IS_OK(result)) {
994 status = result;
995 goto done;
998 if (name_types.ids[0] != SID_NAME_USER) {
999 DEBUG(0,("%s is not a user account (type=%d)\n",
1000 acct_name, name_types.ids[0]));
1001 status = NT_STATUS_INVALID_WORKSTATION;
1002 goto done;
1005 user_rid = user_rids.ids[0];
1007 /* Open handle on user */
1009 status = dcerpc_samr_OpenUser(b, mem_ctx,
1010 &domain_pol,
1011 SEC_FLAG_MAXIMUM_ALLOWED,
1012 user_rid,
1013 &user_pol,
1014 &result);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 goto done;
1018 if (!NT_STATUS_IS_OK(result)) {
1019 status = result;
1020 goto done;
1023 /* Fill in the additional account flags now */
1025 acct_flags |= ACB_PWNOEXP;
1027 /* Set account flags on machine account */
1028 ZERO_STRUCT(user_info.info16);
1029 user_info.info16.acct_flags = acct_flags;
1031 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1032 &user_pol,
1034 &user_info,
1035 &result);
1036 if (!NT_STATUS_IS_OK(status)) {
1037 dcerpc_samr_DeleteUser(b, mem_ctx,
1038 &user_pol,
1039 &result);
1041 libnet_join_set_error_string(mem_ctx, r,
1042 "Failed to set account flags for machine account (%s)\n",
1043 nt_errstr(status));
1044 goto done;
1047 if (!NT_STATUS_IS_OK(result)) {
1048 status = result;
1050 dcerpc_samr_DeleteUser(b, mem_ctx,
1051 &user_pol,
1052 &result);
1054 libnet_join_set_error_string(mem_ctx, r,
1055 "Failed to set account flags for machine account (%s)\n",
1056 nt_errstr(status));
1057 goto done;
1060 /* Set password on machine account - first try level 26 */
1062 init_samr_CryptPasswordEx(r->in.machine_password,
1063 &cli->user_session_key,
1064 &crypt_pwd_ex);
1066 user_info.info26.password = crypt_pwd_ex;
1067 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1069 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1070 &user_pol,
1072 &user_info,
1073 &result);
1075 if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
1077 /* retry with level 24 */
1079 init_samr_CryptPassword(r->in.machine_password,
1080 &cli->user_session_key,
1081 &crypt_pwd);
1083 user_info.info24.password = crypt_pwd;
1084 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1086 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1087 &user_pol,
1089 &user_info,
1090 &result);
1093 if (!NT_STATUS_IS_OK(status)) {
1095 dcerpc_samr_DeleteUser(b, mem_ctx,
1096 &user_pol,
1097 &result);
1099 libnet_join_set_error_string(mem_ctx, r,
1100 "Failed to set password for machine account (%s)\n",
1101 nt_errstr(status));
1102 goto done;
1104 if (!NT_STATUS_IS_OK(result)) {
1105 status = result;
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;
1117 status = NT_STATUS_OK;
1119 done:
1120 if (!pipe_hnd) {
1121 return status;
1124 if (is_valid_policy_hnd(&sam_pol)) {
1125 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1127 if (is_valid_policy_hnd(&domain_pol)) {
1128 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1130 if (is_valid_policy_hnd(&user_pol)) {
1131 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1133 TALLOC_FREE(pipe_hnd);
1135 return status;
1138 /****************************************************************
1139 ****************************************************************/
1141 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
1142 const char *machine_name,
1143 const char *dc_name)
1145 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
1146 struct cli_state *cli = NULL;
1147 struct rpc_pipe_client *pipe_hnd = NULL;
1148 struct rpc_pipe_client *netlogon_pipe = NULL;
1149 NTSTATUS status;
1150 char *machine_password = NULL;
1151 char *machine_account = NULL;
1153 if (!dc_name) {
1154 return NT_STATUS_INVALID_PARAMETER;
1157 if (!secrets_init()) {
1158 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1161 machine_password = secrets_fetch_machine_password(netbios_domain_name,
1162 NULL, NULL);
1163 if (!machine_password) {
1164 return NT_STATUS_NO_TRUST_LSA_SECRET;
1167 if (asprintf(&machine_account, "%s$", machine_name) == -1) {
1168 SAFE_FREE(machine_password);
1169 return NT_STATUS_NO_MEMORY;
1172 status = cli_full_connection(&cli, NULL,
1173 dc_name,
1174 NULL, 0,
1175 "IPC$", "IPC",
1176 machine_account,
1177 NULL,
1178 machine_password,
1180 Undefined);
1181 free(machine_account);
1182 free(machine_password);
1184 if (!NT_STATUS_IS_OK(status)) {
1185 status = cli_full_connection(&cli, NULL,
1186 dc_name,
1187 NULL, 0,
1188 "IPC$", "IPC",
1190 NULL,
1193 Undefined);
1196 if (!NT_STATUS_IS_OK(status)) {
1197 return status;
1200 status = get_schannel_session_key(cli, netbios_domain_name,
1201 &neg_flags, &netlogon_pipe);
1202 if (!NT_STATUS_IS_OK(status)) {
1203 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
1204 cli_shutdown(cli);
1205 return NT_STATUS_OK;
1208 DEBUG(0,("libnet_join_ok: failed to get schannel session "
1209 "key from server %s for domain %s. Error was %s\n",
1210 cli->desthost, netbios_domain_name, nt_errstr(status)));
1211 cli_shutdown(cli);
1212 return status;
1215 if (!lp_client_schannel()) {
1216 cli_shutdown(cli);
1217 return NT_STATUS_OK;
1220 status = cli_rpc_pipe_open_schannel_with_key(
1221 cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
1222 DCERPC_AUTH_LEVEL_PRIVACY,
1223 netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd);
1225 cli_shutdown(cli);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1229 "on netlogon pipe to server %s for domain %s. "
1230 "Error was %s\n",
1231 cli->desthost, netbios_domain_name, nt_errstr(status)));
1232 return status;
1235 return NT_STATUS_OK;
1238 /****************************************************************
1239 ****************************************************************/
1241 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1242 struct libnet_JoinCtx *r)
1244 NTSTATUS status;
1246 status = libnet_join_ok(r->out.netbios_domain_name,
1247 r->in.machine_name,
1248 r->in.dc_name);
1249 if (!NT_STATUS_IS_OK(status)) {
1250 libnet_join_set_error_string(mem_ctx, r,
1251 "failed to verify domain membership after joining: %s",
1252 get_friendly_nt_error_msg(status));
1253 return WERR_SETUP_NOT_JOINED;
1256 return WERR_OK;
1259 /****************************************************************
1260 ****************************************************************/
1262 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1263 struct libnet_UnjoinCtx *r)
1265 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
1266 return false;
1269 if (!secrets_delete_domain_sid(lp_workgroup())) {
1270 return false;
1273 return true;
1276 /****************************************************************
1277 ****************************************************************/
1279 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1280 struct libnet_UnjoinCtx *r)
1282 struct cli_state *cli = NULL;
1283 struct rpc_pipe_client *pipe_hnd = NULL;
1284 struct policy_handle sam_pol, domain_pol, user_pol;
1285 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1286 char *acct_name;
1287 uint32_t user_rid;
1288 struct lsa_String lsa_acct_name;
1289 struct samr_Ids user_rids;
1290 struct samr_Ids name_types;
1291 union samr_UserInfo *info = NULL;
1292 struct dcerpc_binding_handle *b;
1294 ZERO_STRUCT(sam_pol);
1295 ZERO_STRUCT(domain_pol);
1296 ZERO_STRUCT(user_pol);
1298 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1299 r->in.admin_account,
1300 r->in.admin_password,
1301 r->in.use_kerberos,
1302 &cli);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 goto done;
1307 /* Open the domain */
1309 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id,
1310 &pipe_hnd);
1311 if (!NT_STATUS_IS_OK(status)) {
1312 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1313 nt_errstr(status)));
1314 goto done;
1317 b = pipe_hnd->binding_handle;
1319 status = dcerpc_samr_Connect2(b, mem_ctx,
1320 pipe_hnd->desthost,
1321 SEC_FLAG_MAXIMUM_ALLOWED,
1322 &sam_pol,
1323 &result);
1324 if (!NT_STATUS_IS_OK(status)) {
1325 goto done;
1327 if (!NT_STATUS_IS_OK(result)) {
1328 status = result;
1329 goto done;
1332 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1333 &sam_pol,
1334 SEC_FLAG_MAXIMUM_ALLOWED,
1335 r->in.domain_sid,
1336 &domain_pol,
1337 &result);
1338 if (!NT_STATUS_IS_OK(status)) {
1339 goto done;
1341 if (!NT_STATUS_IS_OK(result)) {
1342 status = result;
1343 goto done;
1346 /* Create domain user */
1348 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1349 strlower_m(acct_name);
1351 init_lsa_String(&lsa_acct_name, acct_name);
1353 status = dcerpc_samr_LookupNames(b, mem_ctx,
1354 &domain_pol,
1356 &lsa_acct_name,
1357 &user_rids,
1358 &name_types,
1359 &result);
1361 if (!NT_STATUS_IS_OK(status)) {
1362 goto done;
1364 if (!NT_STATUS_IS_OK(result)) {
1365 status = result;
1366 goto done;
1369 if (name_types.ids[0] != SID_NAME_USER) {
1370 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1371 name_types.ids[0]));
1372 status = NT_STATUS_INVALID_WORKSTATION;
1373 goto done;
1376 user_rid = user_rids.ids[0];
1378 /* Open handle on user */
1380 status = dcerpc_samr_OpenUser(b, mem_ctx,
1381 &domain_pol,
1382 SEC_FLAG_MAXIMUM_ALLOWED,
1383 user_rid,
1384 &user_pol,
1385 &result);
1386 if (!NT_STATUS_IS_OK(status)) {
1387 goto done;
1389 if (!NT_STATUS_IS_OK(result)) {
1390 status = result;
1391 goto done;
1394 /* Get user info */
1396 status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1397 &user_pol,
1399 &info,
1400 &result);
1401 if (!NT_STATUS_IS_OK(status)) {
1402 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1403 goto done;
1405 if (!NT_STATUS_IS_OK(result)) {
1406 status = result;
1407 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1408 goto done;
1411 /* now disable and setuser info */
1413 info->info16.acct_flags |= ACB_DISABLED;
1415 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1416 &user_pol,
1418 info,
1419 &result);
1420 if (!NT_STATUS_IS_OK(status)) {
1421 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1422 goto done;
1424 if (!NT_STATUS_IS_OK(result)) {
1425 status = result;
1426 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1427 goto done;
1429 status = result;
1430 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1432 done:
1433 if (pipe_hnd) {
1434 if (is_valid_policy_hnd(&domain_pol)) {
1435 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1437 if (is_valid_policy_hnd(&sam_pol)) {
1438 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1440 TALLOC_FREE(pipe_hnd);
1443 if (cli) {
1444 cli_shutdown(cli);
1447 return status;
1450 /****************************************************************
1451 ****************************************************************/
1453 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1455 WERROR werr;
1456 struct smbconf_ctx *ctx;
1458 werr = smbconf_init_reg(r, &ctx, NULL);
1459 if (!W_ERROR_IS_OK(werr)) {
1460 goto done;
1463 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1465 werr = smbconf_set_global_parameter(ctx, "security", "user");
1466 W_ERROR_NOT_OK_GOTO_DONE(werr);
1468 werr = smbconf_set_global_parameter(ctx, "workgroup",
1469 r->in.domain_name);
1471 smbconf_delete_global_parameter(ctx, "realm");
1472 goto done;
1475 werr = smbconf_set_global_parameter(ctx, "security", "domain");
1476 W_ERROR_NOT_OK_GOTO_DONE(werr);
1478 werr = smbconf_set_global_parameter(ctx, "workgroup",
1479 r->out.netbios_domain_name);
1480 W_ERROR_NOT_OK_GOTO_DONE(werr);
1482 if (r->out.domain_is_ad) {
1483 werr = smbconf_set_global_parameter(ctx, "security", "ads");
1484 W_ERROR_NOT_OK_GOTO_DONE(werr);
1486 werr = smbconf_set_global_parameter(ctx, "realm",
1487 r->out.dns_domain_name);
1488 W_ERROR_NOT_OK_GOTO_DONE(werr);
1491 done:
1492 smbconf_shutdown(ctx);
1493 return werr;
1496 /****************************************************************
1497 ****************************************************************/
1499 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1501 WERROR werr = WERR_OK;
1502 struct smbconf_ctx *ctx;
1504 werr = smbconf_init_reg(r, &ctx, NULL);
1505 if (!W_ERROR_IS_OK(werr)) {
1506 goto done;
1509 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1511 werr = smbconf_set_global_parameter(ctx, "security", "user");
1512 W_ERROR_NOT_OK_GOTO_DONE(werr);
1514 werr = smbconf_delete_global_parameter(ctx, "workgroup");
1515 W_ERROR_NOT_OK_GOTO_DONE(werr);
1517 smbconf_delete_global_parameter(ctx, "realm");
1520 done:
1521 smbconf_shutdown(ctx);
1522 return werr;
1525 /****************************************************************
1526 ****************************************************************/
1528 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1530 WERROR werr;
1532 if (!W_ERROR_IS_OK(r->out.result)) {
1533 return r->out.result;
1536 if (!r->in.modify_config) {
1537 return WERR_OK;
1540 werr = do_join_modify_vals_config(r);
1541 if (!W_ERROR_IS_OK(werr)) {
1542 return werr;
1545 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1547 r->out.modified_config = true;
1548 r->out.result = werr;
1550 return werr;
1553 /****************************************************************
1554 ****************************************************************/
1556 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1558 WERROR werr;
1560 if (!W_ERROR_IS_OK(r->out.result)) {
1561 return r->out.result;
1564 if (!r->in.modify_config) {
1565 return WERR_OK;
1568 werr = do_unjoin_modify_vals_config(r);
1569 if (!W_ERROR_IS_OK(werr)) {
1570 return werr;
1573 lp_load(get_dyn_CONFIGFILE(),true,false,false,true);
1575 r->out.modified_config = true;
1576 r->out.result = werr;
1578 return werr;
1581 /****************************************************************
1582 ****************************************************************/
1584 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
1585 const char *domain_str,
1586 const char **domain_p,
1587 const char **dc_p)
1589 char *domain = NULL;
1590 char *dc = NULL;
1591 const char *p = NULL;
1593 if (!domain_str || !domain_p || !dc_p) {
1594 return false;
1597 p = strchr_m(domain_str, '\\');
1599 if (p != NULL) {
1600 domain = talloc_strndup(mem_ctx, domain_str,
1601 PTR_DIFF(p, domain_str));
1602 dc = talloc_strdup(mem_ctx, p+1);
1603 if (!dc) {
1604 return false;
1606 } else {
1607 domain = talloc_strdup(mem_ctx, domain_str);
1608 dc = NULL;
1610 if (!domain) {
1611 return false;
1614 *domain_p = domain;
1616 if (!*dc_p && dc) {
1617 *dc_p = dc;
1620 return true;
1623 /****************************************************************
1624 ****************************************************************/
1626 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1627 struct libnet_JoinCtx *r)
1629 if (!r->in.domain_name) {
1630 libnet_join_set_error_string(mem_ctx, r,
1631 "No domain name defined");
1632 return WERR_INVALID_PARAM;
1635 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
1636 &r->in.domain_name,
1637 &r->in.dc_name)) {
1638 libnet_join_set_error_string(mem_ctx, r,
1639 "Failed to parse domain name");
1640 return WERR_INVALID_PARAM;
1643 if (IS_DC) {
1644 return WERR_SETUP_DOMAIN_CONTROLLER;
1647 if (!secrets_init()) {
1648 libnet_join_set_error_string(mem_ctx, r,
1649 "Unable to open secrets database");
1650 return WERR_CAN_NOT_COMPLETE;
1653 return WERR_OK;
1656 /****************************************************************
1657 ****************************************************************/
1659 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
1661 NTSTATUS status;
1663 /* Try adding dom admins to builtin\admins. Only log failures. */
1664 status = create_builtin_administrators(domain_sid);
1665 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1666 DEBUG(10,("Unable to auto-add domain administrators to "
1667 "BUILTIN\\Administrators during join because "
1668 "winbindd must be running."));
1669 } else if (!NT_STATUS_IS_OK(status)) {
1670 DEBUG(5, ("Failed to auto-add domain administrators to "
1671 "BUILTIN\\Administrators during join: %s\n",
1672 nt_errstr(status)));
1675 /* Try adding dom users to builtin\users. Only log failures. */
1676 status = create_builtin_users(domain_sid);
1677 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
1678 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
1679 "during join because winbindd must be running."));
1680 } else if (!NT_STATUS_IS_OK(status)) {
1681 DEBUG(5, ("Failed to auto-add domain administrators to "
1682 "BUILTIN\\Administrators during join: %s\n",
1683 nt_errstr(status)));
1687 /****************************************************************
1688 ****************************************************************/
1690 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1691 struct libnet_JoinCtx *r)
1693 WERROR werr;
1695 if (!W_ERROR_IS_OK(r->out.result)) {
1696 return r->out.result;
1699 werr = do_JoinConfig(r);
1700 if (!W_ERROR_IS_OK(werr)) {
1701 return werr;
1704 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1705 return WERR_OK;
1708 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
1709 if (r->out.dns_domain_name) {
1710 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
1713 #ifdef WITH_ADS
1714 if (r->out.domain_is_ad &&
1715 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1716 ADS_STATUS ads_status;
1718 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1719 if (!ADS_ERR_OK(ads_status)) {
1720 return WERR_GENERAL_FAILURE;
1723 #endif /* WITH_ADS */
1725 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
1727 return WERR_OK;
1730 /****************************************************************
1731 ****************************************************************/
1733 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1735 const char *krb5_cc_env = NULL;
1737 if (r->in.ads) {
1738 ads_destroy(&r->in.ads);
1741 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1742 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1743 unsetenv(KRB5_ENV_CCNAME);
1746 return 0;
1749 /****************************************************************
1750 ****************************************************************/
1752 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1754 const char *krb5_cc_env = NULL;
1756 if (r->in.ads) {
1757 ads_destroy(&r->in.ads);
1760 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1761 if (krb5_cc_env && StrCaseCmp(krb5_cc_env, "MEMORY:libnetjoin")) {
1762 unsetenv(KRB5_ENV_CCNAME);
1765 return 0;
1768 /****************************************************************
1769 ****************************************************************/
1771 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1772 struct libnet_JoinCtx **r)
1774 struct libnet_JoinCtx *ctx;
1775 const char *krb5_cc_env = NULL;
1777 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1778 if (!ctx) {
1779 return WERR_NOMEM;
1782 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1784 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1785 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1787 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1788 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1789 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1790 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1791 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1794 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
1796 *r = ctx;
1798 return WERR_OK;
1801 /****************************************************************
1802 ****************************************************************/
1804 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1805 struct libnet_UnjoinCtx **r)
1807 struct libnet_UnjoinCtx *ctx;
1808 const char *krb5_cc_env = NULL;
1810 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1811 if (!ctx) {
1812 return WERR_NOMEM;
1815 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1817 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1818 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1820 krb5_cc_env = getenv(KRB5_ENV_CCNAME);
1821 if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
1822 krb5_cc_env = talloc_strdup(mem_ctx, "MEMORY:libnetjoin");
1823 W_ERROR_HAVE_NO_MEMORY(krb5_cc_env);
1824 setenv(KRB5_ENV_CCNAME, krb5_cc_env, 1);
1827 *r = ctx;
1829 return WERR_OK;
1832 /****************************************************************
1833 ****************************************************************/
1835 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
1836 struct libnet_JoinCtx *r)
1838 bool valid_security = false;
1839 bool valid_workgroup = false;
1840 bool valid_realm = false;
1842 /* check if configuration is already set correctly */
1844 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
1846 switch (r->out.domain_is_ad) {
1847 case false:
1848 valid_security = (lp_security() == SEC_DOMAIN);
1849 if (valid_workgroup && valid_security) {
1850 /* nothing to be done */
1851 return WERR_OK;
1853 break;
1854 case true:
1855 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
1856 switch (lp_security()) {
1857 case SEC_DOMAIN:
1858 case SEC_ADS:
1859 valid_security = true;
1862 if (valid_workgroup && valid_realm && valid_security) {
1863 /* nothing to be done */
1864 return WERR_OK;
1866 break;
1869 /* check if we are supposed to manipulate configuration */
1871 if (!r->in.modify_config) {
1873 char *wrong_conf = talloc_strdup(mem_ctx, "");
1875 if (!valid_workgroup) {
1876 wrong_conf = talloc_asprintf_append(wrong_conf,
1877 "\"workgroup\" set to '%s', should be '%s'",
1878 lp_workgroup(), r->out.netbios_domain_name);
1879 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1882 if (!valid_realm) {
1883 wrong_conf = talloc_asprintf_append(wrong_conf,
1884 "\"realm\" set to '%s', should be '%s'",
1885 lp_realm(), r->out.dns_domain_name);
1886 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1889 if (!valid_security) {
1890 const char *sec = NULL;
1891 switch (lp_security()) {
1892 case SEC_SHARE: sec = "share"; break;
1893 case SEC_USER: sec = "user"; break;
1894 case SEC_DOMAIN: sec = "domain"; break;
1895 case SEC_ADS: sec = "ads"; break;
1897 wrong_conf = talloc_asprintf_append(wrong_conf,
1898 "\"security\" set to '%s', should be %s",
1899 sec, r->out.domain_is_ad ?
1900 "either 'domain' or 'ads'" : "'domain'");
1901 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
1904 libnet_join_set_error_string(mem_ctx, r,
1905 "Invalid configuration (%s) and configuration modification "
1906 "was not requested", wrong_conf);
1907 return WERR_CAN_NOT_COMPLETE;
1910 /* check if we are able to manipulate configuration */
1912 if (!lp_config_backend_is_registry()) {
1913 libnet_join_set_error_string(mem_ctx, r,
1914 "Configuration manipulation requested but not "
1915 "supported by backend");
1916 return WERR_NOT_SUPPORTED;
1919 return WERR_OK;
1922 /****************************************************************
1923 ****************************************************************/
1925 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1926 struct libnet_JoinCtx *r)
1928 NTSTATUS status;
1929 WERROR werr;
1930 struct cli_state *cli = NULL;
1931 #ifdef WITH_ADS
1932 ADS_STATUS ads_status;
1933 #endif /* WITH_ADS */
1935 if (!r->in.dc_name) {
1936 struct netr_DsRGetDCNameInfo *info;
1937 const char *dc;
1938 status = dsgetdcname(mem_ctx,
1939 r->in.msg_ctx,
1940 r->in.domain_name,
1941 NULL,
1942 NULL,
1943 DS_FORCE_REDISCOVERY |
1944 DS_DIRECTORY_SERVICE_REQUIRED |
1945 DS_WRITABLE_REQUIRED |
1946 DS_RETURN_DNS_NAME,
1947 &info);
1948 if (!NT_STATUS_IS_OK(status)) {
1949 libnet_join_set_error_string(mem_ctx, r,
1950 "failed to find DC for domain %s",
1951 r->in.domain_name,
1952 get_friendly_nt_error_msg(status));
1953 return WERR_DCNOTFOUND;
1956 dc = strip_hostname(info->dc_unc);
1957 r->in.dc_name = talloc_strdup(mem_ctx, dc);
1958 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1961 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
1962 if (!NT_STATUS_IS_OK(status)) {
1963 libnet_join_set_error_string(mem_ctx, r,
1964 "failed to lookup DC info for domain '%s' over rpc: %s",
1965 r->in.domain_name, get_friendly_nt_error_msg(status));
1966 return ntstatus_to_werror(status);
1969 werr = libnet_join_check_config(mem_ctx, r);
1970 if (!W_ERROR_IS_OK(werr)) {
1971 goto done;
1974 #ifdef WITH_ADS
1975 if (r->out.domain_is_ad && r->in.account_ou &&
1976 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
1978 ads_status = libnet_join_connect_ads(mem_ctx, r);
1979 if (!ADS_ERR_OK(ads_status)) {
1980 return WERR_DEFAULT_JOIN_REQUIRED;
1983 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1984 if (!ADS_ERR_OK(ads_status)) {
1985 libnet_join_set_error_string(mem_ctx, r,
1986 "failed to precreate account in ou %s: %s",
1987 r->in.account_ou,
1988 ads_errstr(ads_status));
1989 return WERR_DEFAULT_JOIN_REQUIRED;
1992 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1994 #endif /* WITH_ADS */
1996 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
1997 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
1998 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
1999 } else {
2000 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2002 if (!NT_STATUS_IS_OK(status)) {
2003 libnet_join_set_error_string(mem_ctx, r,
2004 "failed to join domain '%s' over rpc: %s",
2005 r->in.domain_name, get_friendly_nt_error_msg(status));
2006 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2007 return WERR_SETUP_ALREADY_JOINED;
2009 werr = ntstatus_to_werror(status);
2010 goto done;
2013 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2014 werr = WERR_SETUP_NOT_JOINED;
2015 goto done;
2018 werr = WERR_OK;
2020 done:
2021 if (cli) {
2022 cli_shutdown(cli);
2025 return werr;
2028 /****************************************************************
2029 ****************************************************************/
2031 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2032 struct libnet_JoinCtx *r)
2034 WERROR werr;
2035 struct libnet_UnjoinCtx *u = NULL;
2037 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2038 if (!W_ERROR_IS_OK(werr)) {
2039 return werr;
2042 u->in.debug = r->in.debug;
2043 u->in.dc_name = r->in.dc_name;
2044 u->in.domain_name = r->in.domain_name;
2045 u->in.admin_account = r->in.admin_account;
2046 u->in.admin_password = r->in.admin_password;
2047 u->in.modify_config = r->in.modify_config;
2048 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2049 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2051 werr = libnet_Unjoin(mem_ctx, u);
2052 TALLOC_FREE(u);
2054 return werr;
2057 /****************************************************************
2058 ****************************************************************/
2060 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2061 struct libnet_JoinCtx *r)
2063 WERROR werr;
2065 if (r->in.debug) {
2066 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2069 werr = libnet_join_pre_processing(mem_ctx, r);
2070 if (!W_ERROR_IS_OK(werr)) {
2071 goto done;
2074 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2075 werr = libnet_DomainJoin(mem_ctx, r);
2076 if (!W_ERROR_IS_OK(werr)) {
2077 goto done;
2081 werr = libnet_join_post_processing(mem_ctx, r);
2082 if (!W_ERROR_IS_OK(werr)) {
2083 goto done;
2086 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2087 werr = libnet_join_post_verify(mem_ctx, r);
2088 if (!W_ERROR_IS_OK(werr)) {
2089 libnet_join_rollback(mem_ctx, r);
2093 done:
2094 r->out.result = werr;
2096 if (r->in.debug) {
2097 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2099 return werr;
2102 /****************************************************************
2103 ****************************************************************/
2105 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2106 struct libnet_UnjoinCtx *r)
2108 NTSTATUS status;
2110 if (!r->in.domain_sid) {
2111 struct dom_sid sid;
2112 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2113 libnet_unjoin_set_error_string(mem_ctx, r,
2114 "Unable to fetch domain sid: are we joined?");
2115 return WERR_SETUP_NOT_JOINED;
2117 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2118 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2121 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2122 !r->in.delete_machine_account) {
2123 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2124 return WERR_OK;
2127 if (!r->in.dc_name) {
2128 struct netr_DsRGetDCNameInfo *info;
2129 const char *dc;
2130 status = dsgetdcname(mem_ctx,
2131 r->in.msg_ctx,
2132 r->in.domain_name,
2133 NULL,
2134 NULL,
2135 DS_DIRECTORY_SERVICE_REQUIRED |
2136 DS_WRITABLE_REQUIRED |
2137 DS_RETURN_DNS_NAME,
2138 &info);
2139 if (!NT_STATUS_IS_OK(status)) {
2140 libnet_unjoin_set_error_string(mem_ctx, r,
2141 "failed to find DC for domain %s",
2142 r->in.domain_name,
2143 get_friendly_nt_error_msg(status));
2144 return WERR_DCNOTFOUND;
2147 dc = strip_hostname(info->dc_unc);
2148 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2149 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2152 #ifdef WITH_ADS
2153 /* for net ads leave, try to delete the account. If it works,
2154 no sense in disabling. If it fails, we can still try to
2155 disable it. jmcd */
2157 if (r->in.delete_machine_account) {
2158 ADS_STATUS ads_status;
2159 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2160 if (ADS_ERR_OK(ads_status)) {
2161 /* dirty hack */
2162 r->out.dns_domain_name =
2163 talloc_strdup(mem_ctx,
2164 r->in.ads->server.realm);
2165 ads_status =
2166 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2168 if (!ADS_ERR_OK(ads_status)) {
2169 libnet_unjoin_set_error_string(mem_ctx, r,
2170 "failed to remove machine account from AD: %s",
2171 ads_errstr(ads_status));
2172 } else {
2173 r->out.deleted_machine_account = true;
2174 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2175 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2176 return WERR_OK;
2179 #endif /* WITH_ADS */
2181 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2182 "disable". */
2183 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2184 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2185 if (!NT_STATUS_IS_OK(status)) {
2186 libnet_unjoin_set_error_string(mem_ctx, r,
2187 "failed to disable machine account via rpc: %s",
2188 get_friendly_nt_error_msg(status));
2189 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2190 return WERR_SETUP_NOT_JOINED;
2192 return ntstatus_to_werror(status);
2195 r->out.disabled_machine_account = true;
2198 /* If disable succeeded or was not requested at all, we
2199 should be getting rid of our end of things */
2201 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2203 return WERR_OK;
2206 /****************************************************************
2207 ****************************************************************/
2209 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2210 struct libnet_UnjoinCtx *r)
2212 if (!r->in.domain_name) {
2213 libnet_unjoin_set_error_string(mem_ctx, r,
2214 "No domain name defined");
2215 return WERR_INVALID_PARAM;
2218 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2219 &r->in.domain_name,
2220 &r->in.dc_name)) {
2221 libnet_unjoin_set_error_string(mem_ctx, r,
2222 "Failed to parse domain name");
2223 return WERR_INVALID_PARAM;
2226 if (IS_DC) {
2227 return WERR_SETUP_DOMAIN_CONTROLLER;
2230 if (!secrets_init()) {
2231 libnet_unjoin_set_error_string(mem_ctx, r,
2232 "Unable to open secrets database");
2233 return WERR_CAN_NOT_COMPLETE;
2236 return WERR_OK;
2239 /****************************************************************
2240 ****************************************************************/
2242 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2243 struct libnet_UnjoinCtx *r)
2245 saf_delete(r->out.netbios_domain_name);
2246 saf_delete(r->out.dns_domain_name);
2248 return libnet_unjoin_config(r);
2251 /****************************************************************
2252 ****************************************************************/
2254 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2255 struct libnet_UnjoinCtx *r)
2257 WERROR werr;
2259 if (r->in.debug) {
2260 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2263 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2264 if (!W_ERROR_IS_OK(werr)) {
2265 goto done;
2268 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2269 werr = libnet_DomainUnjoin(mem_ctx, r);
2270 if (!W_ERROR_IS_OK(werr)) {
2271 libnet_unjoin_config(r);
2272 goto done;
2276 werr = libnet_unjoin_post_processing(mem_ctx, r);
2277 if (!W_ERROR_IS_OK(werr)) {
2278 goto done;
2281 done:
2282 r->out.result = werr;
2284 if (r->in.debug) {
2285 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);
2288 return werr;