2 * Unix SMB/CIFS implementation.
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/>.
23 #include "libsmb/namequery.h"
24 #include "librpc/gen_ndr/ndr_libnet_join.h"
25 #include "libnet/libnet_join.h"
26 #include "libcli/auth/libcli_auth.h"
27 #include "../librpc/gen_ndr/ndr_samr_c.h"
28 #include "rpc_client/init_samr.h"
29 #include "../librpc/gen_ndr/ndr_lsa_c.h"
30 #include "rpc_client/cli_lsarpc.h"
31 #include "../librpc/gen_ndr/ndr_netlogon.h"
32 #include "rpc_client/cli_netlogon.h"
33 #include "lib/smbconf/smbconf.h"
34 #include "lib/smbconf/smbconf_reg.h"
35 #include "../libds/common/flags.h"
37 #include "rpc_client/init_lsa.h"
38 #include "rpc_client/cli_pipe.h"
39 #include "../libcli/security/security.h"
41 #include "libsmb/libsmb.h"
42 #include "../libcli/smb/smbXcli_base.h"
43 #include "lib/param/loadparm.h"
44 #include "libcli/auth/netlogon_creds_cli.h"
45 #include "auth/credentials/credentials.h"
46 #include "libsmb/dsgetdcname.h"
47 #include "rpc_client/util_netlogon.h"
48 #include "libnet/libnet_join_offline.h"
50 /****************************************************************
51 ****************************************************************/
53 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
56 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
57 DEBUG(1,("libnet_Join:\n%s", str)); \
61 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
62 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
63 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
64 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
66 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
69 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
70 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
74 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
75 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
76 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
77 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
79 /****************************************************************
80 ****************************************************************/
82 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
83 struct libnet_JoinCtx *r,
84 const char *format, ...)
85 PRINTF_ATTRIBUTE(3,4);
87 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
88 struct libnet_JoinCtx *r,
89 const char *format, ...)
93 if (r->out.error_string) {
97 va_start(args, format);
98 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
102 /****************************************************************
103 ****************************************************************/
105 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
106 struct libnet_UnjoinCtx *r,
107 const char *format, ...)
108 PRINTF_ATTRIBUTE(3,4);
110 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
111 struct libnet_UnjoinCtx *r,
112 const char *format, ...)
116 if (r->out.error_string) {
120 va_start(args, format);
121 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
127 /****************************************************************
128 ****************************************************************/
130 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
131 const char *netbios_domain_name,
133 struct cli_credentials *creds,
137 TALLOC_CTX *tmp_ctx = talloc_stackframe();
139 ADS_STRUCT *my_ads = NULL;
141 my_ads = ads_init(tmp_ctx,
147 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
151 status = ads_connect_creds(my_ads, creds);
152 if (!ADS_ERR_OK(status)) {
156 *ads = talloc_move(mem_ctx, &my_ads);
158 status = ADS_SUCCESS;
160 TALLOC_FREE(tmp_ctx);
164 /****************************************************************
165 ****************************************************************/
167 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
168 struct libnet_JoinCtx *r,
169 bool use_machine_creds)
172 struct cli_credentials *creds = NULL;
174 if (use_machine_creds) {
175 const char *username = NULL;
178 if (r->in.machine_name == NULL ||
179 r->in.machine_password == NULL) {
180 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
182 if (r->out.dns_domain_name != NULL) {
183 username = talloc_asprintf(mem_ctx, "%s$@%s",
185 r->out.dns_domain_name);
186 if (username == NULL) {
187 return ADS_ERROR(LDAP_NO_MEMORY);
190 username = talloc_asprintf(mem_ctx, "%s$",
192 if (username == NULL) {
193 return ADS_ERROR(LDAP_NO_MEMORY);
197 ntstatus = ads_simple_creds(mem_ctx,
198 r->out.netbios_domain_name,
200 r->in.machine_password,
202 if (!NT_STATUS_IS_OK(ntstatus)) {
203 return ADS_ERROR_NT(ntstatus);
206 creds = r->in.admin_credentials;
209 status = libnet_connect_ads(r->out.dns_domain_name,
210 r->out.netbios_domain_name,
215 if (!ADS_ERR_OK(status)) {
216 libnet_join_set_error_string(mem_ctx, r,
217 "failed to connect to AD: %s",
222 if (!r->out.netbios_domain_name) {
223 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
224 r->in.ads->server.workgroup);
225 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
228 if (!r->out.dns_domain_name) {
229 r->out.dns_domain_name = talloc_strdup(mem_ctx,
230 r->in.ads->config.realm);
231 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
234 r->out.domain_is_ad = true;
239 /****************************************************************
240 ****************************************************************/
242 static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
243 struct libnet_JoinCtx *r)
245 return libnet_join_connect_ads(mem_ctx, r, false);
248 /****************************************************************
249 ****************************************************************/
251 static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
252 struct libnet_JoinCtx *r)
254 return libnet_join_connect_ads(mem_ctx, r, true);
257 /****************************************************************
258 ****************************************************************/
260 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
261 struct libnet_UnjoinCtx *r)
265 status = libnet_connect_ads(r->in.domain_name,
268 r->in.admin_credentials,
271 if (!ADS_ERR_OK(status)) {
272 libnet_unjoin_set_error_string(mem_ctx, r,
273 "failed to connect to AD: %s",
280 /****************************************************************
281 join a domain using ADS (LDAP mods)
282 ****************************************************************/
284 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
285 struct libnet_JoinCtx *r)
288 LDAPMessage *res = NULL;
289 const char *attrs[] = { "dn", NULL };
292 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
293 if (!ADS_ERR_OK(status)) {
297 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
298 if (!ADS_ERR_OK(status)) {
302 if (ads_count_replies(r->in.ads, res) != 1) {
303 ads_msgfree(r->in.ads, res);
304 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
307 ads_msgfree(r->in.ads, res);
309 /* Attempt to create the machine account and bail if this fails.
310 Assume that the admin wants exactly what they requested */
312 if (r->in.machine_password == NULL) {
313 r->in.machine_password =
314 trust_pw_new_value(mem_ctx,
315 r->in.secure_channel_type,
317 if (r->in.machine_password == NULL) {
318 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
322 status = ads_create_machine_acct(r->in.ads,
324 r->in.machine_password,
326 r->in.desired_encryption_types,
327 r->out.dns_domain_name);
329 if (ADS_ERR_OK(status)) {
330 DBG_WARNING("Machine account successfully created\n");
332 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
333 (status.err.rc == LDAP_ALREADY_EXISTS)) {
334 status = ADS_SUCCESS;
337 if (!ADS_ERR_OK(status)) {
338 DBG_WARNING("Failed to create machine account\n");
342 status = ads_move_machine_acct(r->in.ads,
346 if (!ADS_ERR_OK(status)) {
347 DEBUG(1,("failure to locate/move pre-existing "
348 "machine account\n"));
352 DEBUG(1,("The machine account %s the specified OU.\n",
353 moved ? "was moved into" : "already exists in"));
358 /****************************************************************
359 ****************************************************************/
361 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
362 struct libnet_UnjoinCtx *r)
367 status = libnet_unjoin_connect_ads(mem_ctx, r);
368 if (!ADS_ERR_OK(status)) {
369 libnet_unjoin_set_error_string(mem_ctx, r,
370 "failed to connect to AD: %s",
376 status = ads_leave_realm(r->in.ads, r->in.machine_name);
377 if (!ADS_ERR_OK(status)) {
378 libnet_unjoin_set_error_string(mem_ctx, r,
379 "failed to leave realm: %s",
387 /****************************************************************
388 ****************************************************************/
390 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
391 struct libnet_JoinCtx *r)
394 LDAPMessage *res = NULL;
398 if (!r->in.machine_name) {
399 return ADS_ERROR(LDAP_NO_MEMORY);
402 status = ads_find_machine_acct(r->in.ads,
405 if (!ADS_ERR_OK(status)) {
409 if (ads_count_replies(r->in.ads, res) != 1) {
410 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
414 dn = ads_get_dn(r->in.ads, mem_ctx, res);
416 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
420 r->out.dn = talloc_strdup(mem_ctx, dn);
422 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
426 if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
427 &r->out.set_encryption_types)) {
428 r->out.set_encryption_types = 0;
431 if (!ads_pull_sid(r->in.ads, res, "objectSid", &sid)) {
432 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
436 dom_sid_split_rid(mem_ctx, &sid, NULL, &r->out.account_rid);
438 ads_msgfree(r->in.ads, res);
444 static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx,
445 struct libnet_JoinCtx *r,
451 if (r->in.machine_name == NULL) {
452 return ADS_ERROR_SYSTEM(EINVAL);
455 status = ads_get_service_principal_names(mem_ctx,
464 static ADS_STATUS add_uniq_spn(TALLOC_CTX *mem_ctx, const char *spn,
465 const char ***array, size_t *num)
467 bool ok = ads_element_in_array(*array, *num, spn);
469 ok = add_string_to_array(mem_ctx, spn, array, num);
471 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
477 /****************************************************************
478 Set a machines dNSHostName and servicePrincipalName attributes
479 ****************************************************************/
481 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
482 struct libnet_JoinCtx *r)
484 TALLOC_CTX *frame = talloc_stackframe();
489 const char **spn_array = NULL;
492 const char **netbios_aliases = NULL;
493 const char **addl_hostnames = NULL;
494 const char *dns_hostname = NULL;
498 status = libnet_join_find_machine_acct(mem_ctx, r);
499 if (!ADS_ERR_OK(status)) {
503 status = libnet_join_get_machine_spns(frame,
505 discard_const_p(char **, &spn_array),
507 if (!ADS_ERR_OK(status)) {
508 DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
511 /* Windows only creates HOST/shortname & HOST/fqdn. */
513 spn = talloc_asprintf(frame, "HOST/%s", r->in.machine_name);
515 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
518 if (!strupper_m(spn)) {
519 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
523 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
524 if (!ADS_ERR_OK(status)) {
528 if (r->in.dnshostname != NULL) {
529 fstr_sprintf(my_fqdn, "%s", r->in.dnshostname);
531 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
535 if (!strlower_m(my_fqdn)) {
536 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
540 spn = talloc_asprintf(frame, "HOST/%s", my_fqdn);
542 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
546 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
547 if (!ADS_ERR_OK(status)) {
552 * Register dns_hostname if needed, add_uniq_spn() will avoid
555 dns_hostname = lp_dns_hostname();
556 if (dns_hostname == NULL) {
557 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
561 spn = talloc_asprintf(frame, "HOST/%s", dns_hostname);
563 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
567 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
568 if (!ADS_ERR_OK(status)) {
572 for (netbios_aliases = lp_netbios_aliases();
573 netbios_aliases != NULL && *netbios_aliases != NULL;
576 * Add HOST/NETBIOSNAME
578 spn = talloc_asprintf(frame, "HOST/%s", *netbios_aliases);
580 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
583 if (!strupper_m(spn)) {
584 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
588 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
589 if (!ADS_ERR_OK(status)) {
594 * Add HOST/netbiosname.domainname
596 fstr_sprintf(my_alias, "%s.%s",
599 if (!strlower_m(my_alias)) {
600 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
604 spn = talloc_asprintf(frame, "HOST/%s", my_alias);
606 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
610 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
611 if (!ADS_ERR_OK(status)) {
616 for (addl_hostnames = lp_additional_dns_hostnames();
617 addl_hostnames != NULL && *addl_hostnames != NULL;
620 spn = talloc_asprintf(frame, "HOST/%s", *addl_hostnames);
622 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
626 status = add_uniq_spn(frame, spn, &spn_array, &num_spns);
627 if (!ADS_ERR_OK(status)) {
632 /* make sure to NULL terminate the array */
633 spn_array = talloc_realloc(frame, spn_array, const char *, num_spns + 1);
634 if (spn_array == NULL) {
635 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
638 spn_array[num_spns] = NULL;
640 mods = ads_init_mods(mem_ctx);
642 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
646 /* fields of primary importance */
648 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
649 if (!ADS_ERR_OK(status)) {
653 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
655 if (!ADS_ERR_OK(status)) {
659 addl_hostnames = lp_additional_dns_hostnames();
660 if (addl_hostnames != NULL && *addl_hostnames != NULL) {
661 status = ads_mod_strlist(mem_ctx, &mods,
662 "msDS-AdditionalDnsHostName",
664 if (!ADS_ERR_OK(status)) {
669 status = ads_gen_mod(r->in.ads, r->out.dn, mods);
676 /****************************************************************
677 ****************************************************************/
679 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
680 struct libnet_JoinCtx *r)
685 if (!r->in.create_upn) {
691 status = libnet_join_find_machine_acct(mem_ctx, r);
692 if (!ADS_ERR_OK(status)) {
697 const char *realm = r->out.dns_domain_name;
699 /* in case we are about to generate a keytab during the join
700 * make sure the default upn we create is usable with kinit -k.
703 if (USE_KERBEROS_KEYTAB) {
704 realm = talloc_strdup_upper(mem_ctx,
705 r->out.dns_domain_name);
709 return ADS_ERROR(LDAP_NO_MEMORY);
712 r->in.upn = talloc_asprintf(mem_ctx,
717 return ADS_ERROR(LDAP_NO_MEMORY);
721 /* now do the mods */
723 mods = ads_init_mods(mem_ctx);
725 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
728 /* fields of primary importance */
730 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
731 if (!ADS_ERR_OK(status)) {
732 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
735 return ads_gen_mod(r->in.ads, r->out.dn, mods);
739 /****************************************************************
740 ****************************************************************/
742 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
743 struct libnet_JoinCtx *r)
749 if (!r->in.os_name || !r->in.os_version ) {
755 status = libnet_join_find_machine_acct(mem_ctx, r);
756 if (!ADS_ERR_OK(status)) {
760 /* now do the mods */
762 mods = ads_init_mods(mem_ctx);
764 return ADS_ERROR(LDAP_NO_MEMORY);
767 if (r->in.os_servicepack) {
769 * if blank string then leave os_sp equal to NULL to force
770 * attribute delete (LDAP_MOD_DELETE)
772 if (!strequal(r->in.os_servicepack,"")) {
773 os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
776 os_sp = talloc_asprintf(mem_ctx, "Samba %s",
777 samba_version_string());
779 if (!os_sp && !strequal(r->in.os_servicepack,"")) {
780 return ADS_ERROR(LDAP_NO_MEMORY);
783 /* fields of primary importance */
785 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
787 if (!ADS_ERR_OK(status)) {
791 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
793 if (!ADS_ERR_OK(status)) {
797 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
799 if (!ADS_ERR_OK(status)) {
803 return ads_gen_mod(r->in.ads, r->out.dn, mods);
806 /****************************************************************
807 ****************************************************************/
809 static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
810 struct libnet_JoinCtx *r)
814 const char *etype_list_str;
816 etype_list_str = talloc_asprintf(mem_ctx, "%d",
817 r->in.desired_encryption_types);
818 if (!etype_list_str) {
819 return ADS_ERROR(LDAP_NO_MEMORY);
824 status = libnet_join_find_machine_acct(mem_ctx, r);
825 if (!ADS_ERR_OK(status)) {
829 if (r->in.desired_encryption_types == r->out.set_encryption_types) {
833 /* now do the mods */
835 mods = ads_init_mods(mem_ctx);
837 return ADS_ERROR(LDAP_NO_MEMORY);
840 status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
842 if (!ADS_ERR_OK(status)) {
846 status = ads_gen_mod(r->in.ads, r->out.dn, mods);
847 if (!ADS_ERR_OK(status)) {
851 r->out.set_encryption_types = r->in.desired_encryption_types;
856 /****************************************************************
857 ****************************************************************/
859 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
860 struct libnet_JoinCtx *r)
862 if (!USE_SYSTEM_KEYTAB) {
866 if (ads_keytab_create_default(r->in.ads) != 0) {
873 /****************************************************************
874 ****************************************************************/
876 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
877 struct libnet_JoinCtx *r)
879 uint32_t domain_func;
881 const char *salt = NULL;
882 char *std_salt = NULL;
884 status = ads_domain_func_level(r->in.ads, &domain_func);
885 if (!ADS_ERR_OK(status)) {
886 libnet_join_set_error_string(mem_ctx, r,
887 "failed to determine domain functional level: %s",
892 /* go ahead and setup the default salt */
894 std_salt = kerberos_standard_des_salt();
896 libnet_join_set_error_string(mem_ctx, r,
897 "failed to obtain standard DES salt");
901 salt = talloc_strdup(mem_ctx, std_salt);
908 /* if it's a Windows functional domain, we have to look for the UPN */
910 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
913 upn = ads_get_upn(r->in.ads, mem_ctx,
916 salt = talloc_strdup(mem_ctx, upn);
923 r->out.krb5_salt = salt;
927 /****************************************************************
928 ****************************************************************/
930 static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
931 struct libnet_JoinCtx *r)
934 bool need_etype_update = false;
936 if (r->in.request_offline_join) {
938 * When in the "request offline join" path we can no longer
939 * modify the AD account as we are operating w/o network - gd
945 status = libnet_join_connect_ads_user(mem_ctx, r);
946 if (!ADS_ERR_OK(status)) {
951 status = libnet_join_set_machine_spn(mem_ctx, r);
952 if (!ADS_ERR_OK(status)) {
953 libnet_join_set_error_string(mem_ctx, r,
954 "Failed to set machine spn: %s\n"
955 "Do you have sufficient permissions to create machine "
961 status = libnet_join_set_os_attributes(mem_ctx, r);
962 if (!ADS_ERR_OK(status)) {
963 libnet_join_set_error_string(mem_ctx, r,
964 "failed to set machine os attributes: %s",
969 status = libnet_join_set_machine_upn(mem_ctx, r);
970 if (!ADS_ERR_OK(status)) {
971 libnet_join_set_error_string(mem_ctx, r,
972 "failed to set machine upn: %s",
977 status = libnet_join_find_machine_acct(mem_ctx, r);
978 if (!ADS_ERR_OK(status)) {
982 if (r->in.desired_encryption_types != r->out.set_encryption_types) {
983 uint32_t func_level = 0;
985 status = ads_domain_func_level(r->in.ads, &func_level);
986 if (!ADS_ERR_OK(status)) {
987 libnet_join_set_error_string(mem_ctx, r,
988 "failed to query domain controller functional level: %s",
993 if (func_level >= DS_DOMAIN_FUNCTION_2008) {
994 need_etype_update = true;
998 if (need_etype_update) {
1000 * We need to reconnect as machine account in order
1001 * to update msDS-SupportedEncryptionTypes reliable
1004 TALLOC_FREE(r->in.ads);
1006 status = libnet_join_connect_ads_machine(mem_ctx, r);
1007 if (!ADS_ERR_OK(status)) {
1008 libnet_join_set_error_string(mem_ctx, r,
1009 "Failed to connect as machine account: %s",
1010 ads_errstr(status));
1014 status = libnet_join_set_etypes(mem_ctx, r);
1015 if (!ADS_ERR_OK(status)) {
1016 libnet_join_set_error_string(mem_ctx, r,
1017 "failed to set machine kerberos encryption types: %s",
1018 ads_errstr(status));
1023 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
1024 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1030 static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
1031 struct libnet_JoinCtx *r)
1033 if (!libnet_join_create_keytab(mem_ctx, r)) {
1034 libnet_join_set_error_string(mem_ctx, r,
1035 "failed to create kerberos keytab");
1036 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1041 #endif /* HAVE_ADS */
1043 /****************************************************************
1044 Store the machine password and domain SID
1045 ****************************************************************/
1047 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
1048 struct libnet_JoinCtx *r)
1052 status = secrets_store_JoinCtx(r);
1053 if (!NT_STATUS_IS_OK(status)) {
1054 DBG_ERR("secrets_store_JoinCtx() failed %s\n",
1062 /****************************************************************
1063 Connect dc's IPC$ share
1064 ****************************************************************/
1066 static NTSTATUS libnet_join_connect_dc_ipc(TALLOC_CTX *mem_ctx,
1068 struct cli_credentials *creds,
1069 struct cli_state **cli)
1071 int flags = CLI_FULL_CONNECTION_IPC;
1074 status = cli_full_connection_creds(mem_ctx,
1082 if (!NT_STATUS_IS_OK(status)) {
1086 return NT_STATUS_OK;
1089 /****************************************************************
1090 Lookup domain dc's info
1091 ****************************************************************/
1093 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1094 struct libnet_JoinCtx *r,
1095 struct cli_state **cli)
1097 TALLOC_CTX *frame = talloc_stackframe();
1098 struct rpc_pipe_client *pipe_hnd = NULL;
1099 struct policy_handle lsa_pol;
1100 NTSTATUS status, result;
1101 union lsa_PolicyInformation *info = NULL;
1102 struct cli_credentials *creds = NULL;
1103 struct dcerpc_binding_handle *b;
1105 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
1106 creds = cli_credentials_init_anon(frame);
1107 if (creds == NULL) {
1108 status = NT_STATUS_NO_MEMORY;
1112 creds = r->in.admin_credentials;
1115 status = libnet_join_connect_dc_ipc(mem_ctx,
1119 if (!NT_STATUS_IS_OK(status)) {
1123 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1125 if (!NT_STATUS_IS_OK(status)) {
1126 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
1127 nt_errstr(status)));
1131 b = pipe_hnd->binding_handle;
1133 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1134 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1135 if (!NT_STATUS_IS_OK(status)) {
1139 status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1141 LSA_POLICY_INFO_DNS,
1144 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1145 r->out.domain_is_ad = true;
1146 r->out.netbios_domain_name = info->dns.name.string;
1147 r->out.dns_domain_name = info->dns.dns_domain.string;
1148 r->out.forest_name = info->dns.dns_forest.string;
1149 r->out.domain_guid = info->dns.domain_guid;
1150 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1151 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1154 if (!NT_STATUS_IS_OK(status)) {
1155 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1157 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1160 if (!NT_STATUS_IS_OK(status)) {
1163 if (!NT_STATUS_IS_OK(result)) {
1168 r->out.netbios_domain_name = info->account_domain.name.string;
1169 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1170 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1173 dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1174 TALLOC_FREE(pipe_hnd);
1181 /****************************************************************
1182 Do the domain join unsecure
1183 ****************************************************************/
1185 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1186 struct libnet_JoinCtx *r,
1187 struct cli_state *cli)
1189 TALLOC_CTX *frame = talloc_stackframe();
1190 struct rpc_pipe_client *authenticate_pipe = NULL;
1191 struct rpc_pipe_client *passwordset_pipe = NULL;
1192 struct cli_credentials *cli_creds;
1193 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1194 struct netlogon_creds_CredentialState *creds = NULL;
1195 uint32_t netlogon_flags = 0;
1198 DATA_BLOB new_trust_blob = data_blob_null;
1201 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
1202 &authenticate_pipe);
1203 if (!NT_STATUS_IS_OK(status)) {
1208 if (!r->in.machine_password) {
1209 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1211 r->in.machine_password = trust_pw_new_value(mem_ctx,
1212 r->in.secure_channel_type,
1214 if (r->in.machine_password == NULL) {
1216 return NT_STATUS_NO_MEMORY;
1220 cli_creds = cli_credentials_init(talloc_tos());
1221 if (cli_creds == NULL) {
1223 return NT_STATUS_NO_MEMORY;
1226 cli_credentials_set_username(cli_creds, r->out.account_name,
1228 cli_credentials_set_domain(cli_creds, r->in.domain_name,
1230 cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
1231 cli_credentials_set_secure_channel_type(cli_creds,
1232 r->in.secure_channel_type);
1234 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
1235 cli_credentials_set_password(cli_creds,
1236 r->in.passed_machine_password,
1239 status = rpccli_create_netlogon_creds_ctx(
1240 cli_creds, authenticate_pipe->desthost, r->in.msg_ctx,
1241 frame, &netlogon_creds);
1242 if (!NT_STATUS_IS_OK(status)) {
1247 status = rpccli_setup_netlogon_creds(
1248 cli, NCACN_NP, netlogon_creds, true /* force_reauth */,
1250 if (!NT_STATUS_IS_OK(status)) {
1255 status = netlogon_creds_cli_get(netlogon_creds, frame, &creds);
1256 if (!NT_STATUS_IS_OK(status)) {
1261 netlogon_flags = creds->negotiate_flags;
1264 if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
1265 const char *remote_name = smbXcli_conn_remote_name(cli->conn);
1266 const struct sockaddr_storage *remote_sockaddr =
1267 smbXcli_conn_remote_sockaddr(cli->conn);
1269 status = cli_rpc_pipe_open_schannel_with_creds(
1271 &ndr_table_netlogon,
1277 if (!NT_STATUS_IS_OK(status)) {
1282 passwordset_pipe = authenticate_pipe;
1285 len = strlen(r->in.machine_password);
1286 ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
1287 r->in.machine_password, len,
1288 &new_trust_blob.data,
1289 &new_trust_blob.length);
1291 status = NT_STATUS_UNMAPPABLE_CHARACTER;
1292 if (errno == ENOMEM) {
1293 status = NT_STATUS_NO_MEMORY;
1299 status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1300 passwordset_pipe->binding_handle,
1302 NULL); /* new_version */
1303 if (!NT_STATUS_IS_OK(status)) {
1309 return NT_STATUS_OK;
1312 /****************************************************************
1314 ****************************************************************/
1316 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1317 struct libnet_JoinCtx *r,
1318 struct cli_state *cli)
1320 struct rpc_pipe_client *pipe_hnd = NULL;
1321 struct policy_handle sam_pol, domain_pol, user_pol;
1322 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1324 struct lsa_String lsa_acct_name;
1325 uint32_t acct_flags = ACB_WSTRUST;
1326 struct samr_Ids user_rids;
1327 struct samr_Ids name_types;
1328 union samr_UserInfo user_info;
1329 struct dcerpc_binding_handle *b = NULL;
1330 unsigned int old_timeout = 0;
1332 DATA_BLOB session_key = data_blob_null;
1333 struct samr_CryptPassword crypt_pwd;
1334 struct samr_CryptPasswordEx crypt_pwd_ex;
1336 ZERO_STRUCT(sam_pol);
1337 ZERO_STRUCT(domain_pol);
1338 ZERO_STRUCT(user_pol);
1340 switch (r->in.secure_channel_type) {
1341 case SEC_CHAN_WKSTA:
1342 acct_flags = ACB_WSTRUST;
1345 acct_flags = ACB_SVRTRUST;
1348 return NT_STATUS_INVALID_PARAMETER;
1351 if (!r->in.machine_password) {
1352 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1354 r->in.machine_password = trust_pw_new_value(mem_ctx,
1355 r->in.secure_channel_type,
1357 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1360 /* Open the domain */
1362 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1364 if (!NT_STATUS_IS_OK(status)) {
1365 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1366 nt_errstr(status)));
1370 b = pipe_hnd->binding_handle;
1372 status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1373 if (!NT_STATUS_IS_OK(status)) {
1374 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1375 nt_errstr(status)));
1379 status = dcerpc_samr_Connect2(b, mem_ctx,
1381 SAMR_ACCESS_ENUM_DOMAINS
1382 | SAMR_ACCESS_LOOKUP_DOMAIN,
1385 if (!NT_STATUS_IS_OK(status)) {
1388 if (!NT_STATUS_IS_OK(result)) {
1393 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1395 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1396 | SAMR_DOMAIN_ACCESS_CREATE_USER
1397 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1401 if (!NT_STATUS_IS_OK(status)) {
1404 if (!NT_STATUS_IS_OK(result)) {
1409 /* Create domain user */
1411 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1412 if (!strlower_m(acct_name)) {
1413 status = NT_STATUS_INVALID_PARAMETER;
1417 init_lsa_String(&lsa_acct_name, acct_name);
1419 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1420 uint32_t access_desired =
1421 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1422 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1423 SAMR_USER_ACCESS_SET_PASSWORD |
1424 SAMR_USER_ACCESS_GET_ATTRIBUTES |
1425 SAMR_USER_ACCESS_SET_ATTRIBUTES;
1426 uint32_t access_granted = 0;
1428 DEBUG(10,("Creating account with desired access mask: %d\n",
1431 status = dcerpc_samr_CreateUser2(b, mem_ctx,
1438 &r->out.account_rid,
1440 if (!NT_STATUS_IS_OK(status)) {
1445 if (!NT_STATUS_IS_OK(status) &&
1446 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1448 DEBUG(10,("Creation of workstation account failed: %s\n",
1449 nt_errstr(status)));
1451 /* If NT_STATUS_ACCESS_DENIED then we have a valid
1452 username/password combo but the user does not have
1453 administrator access. */
1455 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1456 libnet_join_set_error_string(mem_ctx, r,
1457 "User specified does not have "
1458 "administrator privileges");
1464 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1465 if (!(r->in.join_flags &
1466 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1471 /* We *must* do this.... don't ask... */
1473 if (NT_STATUS_IS_OK(status)) {
1474 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1478 status = dcerpc_samr_LookupNames(b, mem_ctx,
1485 if (!NT_STATUS_IS_OK(status)) {
1488 if (!NT_STATUS_IS_OK(result)) {
1492 if (user_rids.count != 1) {
1493 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1496 if (name_types.count != 1) {
1497 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1501 if (name_types.ids[0] != SID_NAME_USER) {
1502 DEBUG(0,("%s is not a user account (type=%d)\n",
1503 acct_name, name_types.ids[0]));
1504 status = NT_STATUS_INVALID_WORKSTATION;
1508 r->out.account_rid = user_rids.ids[0];
1510 /* Open handle on user */
1512 status = dcerpc_samr_OpenUser(b, mem_ctx,
1514 SEC_FLAG_MAXIMUM_ALLOWED,
1518 if (!NT_STATUS_IS_OK(status)) {
1521 if (!NT_STATUS_IS_OK(result)) {
1526 /* Fill in the additional account flags now */
1528 acct_flags |= ACB_PWNOEXP;
1530 /* Set account flags on machine account */
1531 ZERO_STRUCT(user_info.info16);
1532 user_info.info16.acct_flags = acct_flags;
1534 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1536 UserControlInformation,
1539 if (!NT_STATUS_IS_OK(status)) {
1540 dcerpc_samr_DeleteUser(b, mem_ctx,
1544 libnet_join_set_error_string(mem_ctx, r,
1545 "Failed to set account flags for machine account (%s)\n",
1550 if (!NT_STATUS_IS_OK(result)) {
1553 dcerpc_samr_DeleteUser(b, mem_ctx,
1557 libnet_join_set_error_string(mem_ctx, r,
1558 "Failed to set account flags for machine account (%s)\n",
1563 /* Set password on machine account - first try level 26 */
1566 * increase the timeout as password filter modules on the DC
1567 * might delay the operation for a significant amount of time
1569 old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1571 status = init_samr_CryptPasswordEx(r->in.machine_password,
1574 if (!NT_STATUS_IS_OK(status)) {
1578 user_info.info26.password = crypt_pwd_ex;
1579 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1581 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1583 UserInternal5InformationNew,
1587 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1589 /* retry with level 24 */
1591 status = init_samr_CryptPassword(r->in.machine_password,
1594 if (!NT_STATUS_IS_OK(status)) {
1598 user_info.info24.password = crypt_pwd;
1599 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1601 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1603 UserInternal5Information,
1609 old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1611 if (!NT_STATUS_IS_OK(status)) {
1613 dcerpc_samr_DeleteUser(b, mem_ctx,
1617 libnet_join_set_error_string(mem_ctx, r,
1618 "Failed to set password for machine account (%s)\n",
1622 if (!NT_STATUS_IS_OK(result)) {
1625 dcerpc_samr_DeleteUser(b, mem_ctx,
1629 libnet_join_set_error_string(mem_ctx, r,
1630 "Failed to set password for machine account (%s)\n",
1635 status = NT_STATUS_OK;
1642 data_blob_clear_free(&session_key);
1644 if (is_valid_policy_hnd(&sam_pol)) {
1645 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1647 if (is_valid_policy_hnd(&domain_pol)) {
1648 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1650 if (is_valid_policy_hnd(&user_pol)) {
1651 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1653 TALLOC_FREE(pipe_hnd);
1658 /****************************************************************
1659 ****************************************************************/
1661 NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1662 const char *netbios_domain_name,
1663 const char *dc_name,
1664 enum credentials_use_kerberos kerberos_state)
1666 TALLOC_CTX *frame = talloc_stackframe();
1667 struct cli_state *cli = NULL;
1668 struct rpc_pipe_client *netlogon_pipe = NULL;
1669 struct cli_credentials *cli_creds = NULL;
1670 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1671 struct netlogon_creds_CredentialState *creds = NULL;
1672 uint32_t netlogon_flags = 0;
1674 int flags = CLI_FULL_CONNECTION_IPC;
1675 const char *remote_name = NULL;
1676 const struct sockaddr_storage *remote_sockaddr = NULL;
1680 return NT_STATUS_INVALID_PARAMETER;
1683 if (!secrets_init()) {
1685 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1688 status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1690 if (!NT_STATUS_IS_OK(status)) {
1695 /* we don't want any old password */
1696 cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1698 cli_credentials_set_kerberos_state(cli_creds,
1702 status = cli_full_connection_creds(frame,
1711 if (!NT_STATUS_IS_OK(status)) {
1712 struct cli_credentials *anon_creds = NULL;
1714 anon_creds = cli_credentials_init_anon(frame);
1715 if (anon_creds == NULL) {
1717 return NT_STATUS_NO_MEMORY;
1720 status = cli_full_connection_creds(frame,
1730 if (!NT_STATUS_IS_OK(status)) {
1735 status = rpccli_create_netlogon_creds_ctx(cli_creds,
1740 if (!NT_STATUS_IS_OK(status)) {
1746 status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
1748 true, /* force_reauth */
1750 if (!NT_STATUS_IS_OK(status)) {
1751 DEBUG(0,("connect_to_domain_password_server: "
1752 "unable to open the domain client session to "
1753 "machine %s. Flags[0x%08X] Error was : %s.\n",
1754 dc_name, (unsigned)netlogon_flags,
1755 nt_errstr(status)));
1761 status = netlogon_creds_cli_get(netlogon_creds,
1764 if (!NT_STATUS_IS_OK(status)) {
1769 netlogon_flags = creds->negotiate_flags;
1772 if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1775 return NT_STATUS_OK;
1778 remote_name = smbXcli_conn_remote_name(cli->conn);
1779 remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn);
1781 status = cli_rpc_pipe_open_schannel_with_creds(
1782 cli, &ndr_table_netlogon, NCACN_NP,
1788 TALLOC_FREE(netlogon_pipe);
1790 if (!NT_STATUS_IS_OK(status)) {
1791 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1792 "on netlogon pipe to server %s for domain %s. "
1795 netbios_domain_name, nt_errstr(status)));
1803 return NT_STATUS_OK;
1806 /****************************************************************
1807 ****************************************************************/
1809 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1810 struct libnet_JoinCtx *r)
1813 enum credentials_use_kerberos kerberos_state = CRED_USE_KERBEROS_DESIRED;
1815 if (r->in.admin_credentials != NULL) {
1816 kerberos_state = cli_credentials_get_kerberos_state(
1817 r->in.admin_credentials);
1820 status = libnet_join_ok(r->in.msg_ctx,
1821 r->out.netbios_domain_name,
1824 if (!NT_STATUS_IS_OK(status)) {
1825 libnet_join_set_error_string(mem_ctx, r,
1826 "failed to verify domain membership after joining: %s",
1827 get_friendly_nt_error_msg(status));
1828 return WERR_NERR_SETUPNOTJOINED;
1834 /****************************************************************
1835 ****************************************************************/
1837 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1838 struct libnet_UnjoinCtx *r)
1841 * TODO: use values from 'struct libnet_UnjoinCtx' ?
1843 return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
1846 /****************************************************************
1847 ****************************************************************/
1849 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1850 struct libnet_UnjoinCtx *r)
1852 struct cli_state *cli = NULL;
1853 struct rpc_pipe_client *pipe_hnd = NULL;
1854 struct policy_handle sam_pol, domain_pol, user_pol;
1855 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1858 struct lsa_String lsa_acct_name;
1859 struct samr_Ids user_rids;
1860 struct samr_Ids name_types;
1861 union samr_UserInfo *info = NULL;
1862 struct dcerpc_binding_handle *b = NULL;
1864 ZERO_STRUCT(sam_pol);
1865 ZERO_STRUCT(domain_pol);
1866 ZERO_STRUCT(user_pol);
1868 status = libnet_join_connect_dc_ipc(mem_ctx,
1870 r->in.admin_credentials,
1872 if (!NT_STATUS_IS_OK(status)) {
1876 /* Open the domain */
1878 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1880 if (!NT_STATUS_IS_OK(status)) {
1881 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1882 nt_errstr(status)));
1886 b = pipe_hnd->binding_handle;
1888 status = dcerpc_samr_Connect2(b, mem_ctx,
1890 SEC_FLAG_MAXIMUM_ALLOWED,
1893 if (!NT_STATUS_IS_OK(status)) {
1896 if (!NT_STATUS_IS_OK(result)) {
1901 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1903 SEC_FLAG_MAXIMUM_ALLOWED,
1907 if (!NT_STATUS_IS_OK(status)) {
1910 if (!NT_STATUS_IS_OK(result)) {
1915 /* Create domain user */
1917 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1918 if (!strlower_m(acct_name)) {
1919 status = NT_STATUS_INVALID_PARAMETER;
1923 init_lsa_String(&lsa_acct_name, acct_name);
1925 status = dcerpc_samr_LookupNames(b, mem_ctx,
1933 if (!NT_STATUS_IS_OK(status)) {
1936 if (!NT_STATUS_IS_OK(result)) {
1940 if (user_rids.count != 1) {
1941 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1944 if (name_types.count != 1) {
1945 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1949 if (name_types.ids[0] != SID_NAME_USER) {
1950 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1951 name_types.ids[0]));
1952 status = NT_STATUS_INVALID_WORKSTATION;
1956 user_rid = user_rids.ids[0];
1958 /* Open handle on user */
1960 status = dcerpc_samr_OpenUser(b, mem_ctx,
1962 SEC_FLAG_MAXIMUM_ALLOWED,
1966 if (!NT_STATUS_IS_OK(status)) {
1969 if (!NT_STATUS_IS_OK(result)) {
1976 status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1981 if (!NT_STATUS_IS_OK(status)) {
1982 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1985 if (!NT_STATUS_IS_OK(result)) {
1987 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1991 /* now disable and setuser info */
1993 info->info16.acct_flags |= ACB_DISABLED;
1995 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
2000 if (!NT_STATUS_IS_OK(status)) {
2001 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2004 if (!NT_STATUS_IS_OK(result)) {
2006 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2010 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
2013 if (pipe_hnd && b) {
2014 if (is_valid_policy_hnd(&domain_pol)) {
2015 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
2017 if (is_valid_policy_hnd(&sam_pol)) {
2018 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
2020 TALLOC_FREE(pipe_hnd);
2030 /****************************************************************
2031 ****************************************************************/
2033 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
2035 WERROR werr = WERR_OK;
2037 struct smbconf_ctx *ctx;
2039 err = smbconf_init_reg(r, &ctx, NULL);
2040 if (!SBC_ERROR_IS_OK(err)) {
2041 werr = WERR_SERVICE_DOES_NOT_EXIST;
2045 err = smbconf_set_global_parameter(ctx, "netbios name",
2046 r->in.machine_name);
2047 if (!SBC_ERROR_IS_OK(err)) {
2048 werr = WERR_SERVICE_DOES_NOT_EXIST;
2052 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2054 err = smbconf_set_global_parameter(ctx, "security", "user");
2055 if (!SBC_ERROR_IS_OK(err)) {
2056 werr = WERR_SERVICE_DOES_NOT_EXIST;
2060 err = smbconf_set_global_parameter(ctx, "workgroup",
2062 if (!SBC_ERROR_IS_OK(err)) {
2063 werr = WERR_SERVICE_DOES_NOT_EXIST;
2067 smbconf_delete_global_parameter(ctx, "realm");
2071 err = smbconf_set_global_parameter(ctx, "security", "domain");
2072 if (!SBC_ERROR_IS_OK(err)) {
2073 werr = WERR_SERVICE_DOES_NOT_EXIST;
2077 err = smbconf_set_global_parameter(ctx, "workgroup",
2078 r->out.netbios_domain_name);
2079 if (!SBC_ERROR_IS_OK(err)) {
2080 werr = WERR_SERVICE_DOES_NOT_EXIST;
2084 if (r->out.domain_is_ad) {
2085 err = smbconf_set_global_parameter(ctx, "security", "ads");
2086 if (!SBC_ERROR_IS_OK(err)) {
2087 werr = WERR_SERVICE_DOES_NOT_EXIST;
2091 err = smbconf_set_global_parameter(ctx, "realm",
2092 r->out.dns_domain_name);
2093 if (!SBC_ERROR_IS_OK(err)) {
2094 werr = WERR_SERVICE_DOES_NOT_EXIST;
2100 smbconf_shutdown(ctx);
2104 /****************************************************************
2105 ****************************************************************/
2107 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
2109 WERROR werr = WERR_OK;
2111 struct smbconf_ctx *ctx;
2113 err = smbconf_init_reg(r, &ctx, NULL);
2114 if (!SBC_ERROR_IS_OK(err)) {
2115 werr = WERR_SERVICE_DOES_NOT_EXIST;
2119 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2121 err = smbconf_set_global_parameter(ctx, "security", "user");
2122 if (!SBC_ERROR_IS_OK(err)) {
2123 werr = WERR_SERVICE_DOES_NOT_EXIST;
2127 err = smbconf_delete_global_parameter(ctx, "workgroup");
2128 if (!SBC_ERROR_IS_OK(err)) {
2129 werr = WERR_SERVICE_DOES_NOT_EXIST;
2133 smbconf_delete_global_parameter(ctx, "realm");
2137 smbconf_shutdown(ctx);
2141 /****************************************************************
2142 ****************************************************************/
2144 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
2148 if (!W_ERROR_IS_OK(r->out.result)) {
2149 return r->out.result;
2152 if (!r->in.modify_config) {
2156 werr = do_join_modify_vals_config(r);
2157 if (!W_ERROR_IS_OK(werr)) {
2161 lp_load_global(get_dyn_CONFIGFILE());
2163 r->out.modified_config = true;
2164 r->out.result = werr;
2169 /****************************************************************
2170 ****************************************************************/
2172 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2176 if (!W_ERROR_IS_OK(r->out.result)) {
2177 return r->out.result;
2180 if (!r->in.modify_config) {
2184 werr = do_unjoin_modify_vals_config(r);
2185 if (!W_ERROR_IS_OK(werr)) {
2189 lp_load_global(get_dyn_CONFIGFILE());
2191 r->out.modified_config = true;
2192 r->out.result = werr;
2197 /****************************************************************
2198 ****************************************************************/
2200 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
2201 const char *domain_str,
2202 const char **domain_p,
2205 char *domain = NULL;
2207 const char *p = NULL;
2209 if (!domain_str || !domain_p || !dc_p) {
2213 p = strchr_m(domain_str, '\\');
2216 domain = talloc_strndup(mem_ctx, domain_str,
2217 PTR_DIFF(p, domain_str));
2218 dc = talloc_strdup(mem_ctx, p+1);
2223 domain = talloc_strdup(mem_ctx, domain_str);
2239 /****************************************************************
2240 ****************************************************************/
2242 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2243 struct libnet_JoinCtx *r)
2245 if (!r->in.domain_name) {
2246 libnet_join_set_error_string(mem_ctx, r,
2247 "No domain name defined");
2248 return WERR_INVALID_PARAMETER;
2251 if (strlen(r->in.machine_name) > 15) {
2252 libnet_join_set_error_string(mem_ctx, r,
2253 "Our netbios name can be at most 15 chars long, "
2254 "\"%s\" is %u chars long\n",
2256 (unsigned int)strlen(r->in.machine_name));
2257 return WERR_INVALID_PARAMETER;
2260 r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
2261 r->in.machine_name);
2262 if (r->out.account_name == NULL) {
2263 libnet_join_set_error_string(mem_ctx, r,
2264 "Unable to construct r->out.account_name");
2265 return WERR_NOT_ENOUGH_MEMORY;
2268 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2271 libnet_join_set_error_string(mem_ctx, r,
2272 "Failed to parse domain name");
2273 return WERR_INVALID_PARAMETER;
2276 if (r->in.request_offline_join) {
2278 * When in the "request offline join" path we do not have admin
2279 * credentials available so we can skip the next steps - gd
2284 if (r->in.provision_computer_account_only) {
2286 * When in the "provision_computer_account_only" path we do not
2287 * need to have access to secrets.tdb at all - gd
2292 if (!secrets_init()) {
2293 libnet_join_set_error_string(mem_ctx, r,
2294 "Unable to open secrets database");
2295 return WERR_CAN_NOT_COMPLETE;
2301 /****************************************************************
2302 ****************************************************************/
2304 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2308 /* Try adding dom admins to builtin\admins. Only log failures. */
2309 status = create_builtin_administrators(domain_sid);
2310 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2311 DEBUG(10,("Unable to auto-add domain administrators to "
2312 "BUILTIN\\Administrators during join because "
2313 "winbindd must be running.\n"));
2314 } else if (!NT_STATUS_IS_OK(status)) {
2315 DEBUG(5, ("Failed to auto-add domain administrators to "
2316 "BUILTIN\\Administrators during join: %s\n",
2317 nt_errstr(status)));
2320 /* Try adding dom users to builtin\users. Only log failures. */
2321 status = create_builtin_users(domain_sid);
2322 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2323 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2324 "during join because winbindd must be running.\n"));
2325 } else if (!NT_STATUS_IS_OK(status)) {
2326 DEBUG(5, ("Failed to auto-add domain administrators to "
2327 "BUILTIN\\Administrators during join: %s\n",
2328 nt_errstr(status)));
2331 /* Try adding dom guests to builtin\guests. Only log failures. */
2332 status = create_builtin_guests(domain_sid);
2333 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2334 DEBUG(10,("Unable to auto-add domain guests to "
2335 "BUILTIN\\Guests during join because "
2336 "winbindd must be running.\n"));
2337 } else if (!NT_STATUS_IS_OK(status)) {
2338 DEBUG(5, ("Failed to auto-add domain guests to "
2339 "BUILTIN\\Guests during join: %s\n",
2340 nt_errstr(status)));
2344 /****************************************************************
2345 ****************************************************************/
2347 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2348 struct libnet_JoinCtx *r)
2352 if (!W_ERROR_IS_OK(r->out.result)) {
2353 return r->out.result;
2356 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2357 werr = do_JoinConfig(r);
2358 if (!W_ERROR_IS_OK(werr)) {
2366 if (r->out.domain_is_ad &&
2367 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2368 ADS_STATUS ads_status;
2370 ads_status = libnet_join_post_processing_ads_modify(mem_ctx, r);
2371 if (!ADS_ERR_OK(ads_status)) {
2372 return WERR_GEN_FAILURE;
2375 #endif /* HAVE_ADS */
2377 if (r->in.provision_computer_account_only) {
2379 * When we only provision a computer account we are done here - gd.
2384 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2385 if (r->out.dns_domain_name) {
2386 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2389 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2390 return WERR_NERR_SETUPNOTJOINED;
2393 werr = do_JoinConfig(r);
2394 if (!W_ERROR_IS_OK(werr)) {
2399 if (r->out.domain_is_ad &&
2400 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2401 ADS_STATUS ads_status;
2403 ads_status = libnet_join_post_processing_ads_sync(mem_ctx, r);
2404 if (!ADS_ERR_OK(ads_status)) {
2405 return WERR_GEN_FAILURE;
2408 #endif /* HAVE_ADS */
2410 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2415 /****************************************************************
2416 ****************************************************************/
2418 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2420 TALLOC_FREE(r->in.ads);
2425 /****************************************************************
2426 ****************************************************************/
2428 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2430 TALLOC_FREE(r->in.ads);
2435 /****************************************************************
2436 ****************************************************************/
2438 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2439 struct libnet_JoinCtx **r)
2441 struct libnet_JoinCtx *ctx;
2443 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2445 return WERR_NOT_ENOUGH_MEMORY;
2448 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2450 ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2451 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2453 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2455 ctx->in.desired_encryption_types = 0;
2456 ctx->in.desired_encryption_types |= ENC_RC4_HMAC_MD5;
2457 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2458 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2465 /****************************************************************
2466 ****************************************************************/
2468 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2469 struct libnet_UnjoinCtx **r)
2471 struct libnet_UnjoinCtx *ctx;
2473 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2475 return WERR_NOT_ENOUGH_MEMORY;
2478 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2480 ctx->in.machine_name = talloc_strdup(ctx, lp_netbios_name());
2481 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2488 /****************************************************************
2489 ****************************************************************/
2491 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2492 struct libnet_JoinCtx *r)
2494 bool valid_security = false;
2495 bool valid_workgroup = false;
2496 bool valid_realm = false;
2497 bool valid_hostname = false;
2498 bool ignored_realm = false;
2500 /* check if configuration is already set correctly */
2502 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2503 valid_hostname = strequal(lp_netbios_name(), r->in.machine_name);
2505 switch (r->out.domain_is_ad) {
2507 valid_security = (lp_security() == SEC_DOMAIN)
2508 || (lp_server_role() == ROLE_DOMAIN_PDC)
2509 || (lp_server_role() == ROLE_DOMAIN_BDC);
2510 if (valid_workgroup && valid_security) {
2511 /* nothing to be done */
2516 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2517 switch (lp_security()) {
2519 if (!valid_realm && lp_winbind_rpc_only()) {
2521 ignored_realm = true;
2526 valid_security = true;
2529 if (valid_workgroup && valid_realm && valid_security &&
2531 if (ignored_realm && !r->in.modify_config)
2533 libnet_join_set_error_string(mem_ctx, r,
2534 "Warning: ignoring realm when "
2535 "joining AD domain with "
2536 "'security=domain' and "
2537 "'winbind rpc only = yes'. "
2538 "(realm set to '%s', "
2539 "should be '%s').", lp_realm(),
2540 r->out.dns_domain_name);
2542 /* nothing to be done */
2548 /* check if we are supposed to manipulate configuration */
2550 if (!r->in.modify_config) {
2552 char *wrong_conf = talloc_strdup(mem_ctx, "");
2554 if (!valid_hostname) {
2555 wrong_conf = talloc_asprintf_append(wrong_conf,
2556 "\"netbios name\" set to '%s', should be '%s'",
2557 lp_netbios_name(), r->in.machine_name);
2558 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2561 if (!valid_workgroup) {
2562 wrong_conf = talloc_asprintf_append(wrong_conf,
2563 "\"workgroup\" set to '%s', should be '%s'",
2564 lp_workgroup(), r->out.netbios_domain_name);
2565 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2569 wrong_conf = talloc_asprintf_append(wrong_conf,
2570 "\"realm\" set to '%s', should be '%s'",
2571 lp_realm(), r->out.dns_domain_name);
2572 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2575 if (!valid_security) {
2576 const char *sec = NULL;
2577 switch (lp_security()) {
2578 case SEC_USER: sec = "user"; break;
2579 case SEC_DOMAIN: sec = "domain"; break;
2580 case SEC_ADS: sec = "ads"; break;
2582 wrong_conf = talloc_asprintf_append(wrong_conf,
2583 "\"security\" set to '%s', should be %s",
2584 sec, r->out.domain_is_ad ?
2585 "either 'domain' or 'ads'" : "'domain'");
2586 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2589 libnet_join_set_error_string(mem_ctx, r,
2590 "Invalid configuration (%s) and configuration modification "
2591 "was not requested", wrong_conf);
2592 return WERR_CAN_NOT_COMPLETE;
2595 /* check if we are able to manipulate configuration */
2597 if (!lp_config_backend_is_registry()) {
2598 libnet_join_set_error_string(mem_ctx, r,
2599 "Configuration manipulation requested but not "
2600 "supported by backend");
2601 return WERR_NOT_SUPPORTED;
2607 /****************************************************************
2608 ****************************************************************/
2610 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2611 struct libnet_JoinCtx *r)
2615 struct cli_state *cli = NULL;
2617 ADS_STATUS ads_status;
2618 #endif /* HAVE_ADS */
2619 const char *pre_connect_realm = NULL;
2620 const char *sitename = NULL;
2621 struct netr_DsRGetDCNameInfo *info;
2623 uint32_t name_type_flags = 0;
2625 /* Before contacting a DC, we can securely know
2626 * the realm only if the user specifies it.
2628 if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2629 pre_connect_realm = r->in.domain_name;
2632 if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2633 name_type_flags = DS_IS_DNS_NAME;
2634 } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2635 name_type_flags = DS_IS_FLAT_NAME;
2638 if (r->in.dc_name) {
2639 status = dsgetonedcname(mem_ctx,
2643 DS_DIRECTORY_SERVICE_REQUIRED |
2644 DS_WRITABLE_REQUIRED |
2645 DS_RETURN_DNS_NAME |
2649 status = dsgetdcname(mem_ctx,
2654 DS_FORCE_REDISCOVERY |
2655 DS_DIRECTORY_SERVICE_REQUIRED |
2656 DS_WRITABLE_REQUIRED |
2657 DS_RETURN_DNS_NAME |
2661 if (!NT_STATUS_IS_OK(status)) {
2662 libnet_join_set_error_string(mem_ctx, r,
2663 "failed to find DC for domain %s - %s",
2665 get_friendly_nt_error_msg(status));
2666 return WERR_NERR_DCNOTFOUND;
2669 dc = strip_hostname(info->dc_unc);
2670 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2671 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2673 if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2674 info->dc_address[1] != '\\') {
2675 DBG_ERR("ill-formed DC address '%s'\n",
2677 return WERR_NERR_DCNOTFOUND;
2680 sitename = info->dc_site_name;
2681 /* info goes out of scope but the memory stays
2682 allocated on the talloc context */
2684 /* return the allocated netr_DsRGetDCNameInfo struct */
2685 r->out.dcinfo = info;
2687 if (pre_connect_realm != NULL) {
2688 struct sockaddr_storage ss = {0};
2689 const char *numeric_dcip = info->dc_address + 2;
2691 if (numeric_dcip[0] == '\0') {
2692 if (!interpret_string_addr(&ss, numeric_dcip,
2695 "cannot parse IP address '%s' of DC '%s'\n",
2696 numeric_dcip, r->in.dc_name);
2697 return WERR_NERR_DCNOTFOUND;
2700 if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2702 "cannot resolve IP address of DC '%s'\n",
2704 return WERR_NERR_DCNOTFOUND;
2708 /* The domain parameter is only used as modifier
2709 * to krb5.conf file name. _JOIN_ is not a valid
2710 * NetBIOS name so it cannot clash with another domain
2713 create_local_private_krb5_conf_for_domain(pre_connect_realm,
2719 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2720 if (!NT_STATUS_IS_OK(status)) {
2721 libnet_join_set_error_string(mem_ctx, r,
2722 "failed to lookup DC info for domain '%s' over rpc: %s",
2723 r->in.domain_name, get_friendly_nt_error_msg(status));
2724 return ntstatus_to_werror(status);
2727 werr = libnet_join_check_config(mem_ctx, r);
2728 if (!W_ERROR_IS_OK(werr)) {
2729 if (!r->in.provision_computer_account_only) {
2732 /* do not fail when only provisioning */
2737 if (r->out.domain_is_ad) {
2738 create_local_private_krb5_conf_for_domain(
2739 r->out.dns_domain_name, r->out.netbios_domain_name,
2740 sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2743 if (r->out.domain_is_ad &&
2744 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2746 const char *initial_account_ou = r->in.account_ou;
2749 * we want to create the msDS-SupportedEncryptionTypes attribute
2750 * as early as possible so always try an LDAP create as the user
2751 * first. We copy r->in.account_ou because it may be changed
2752 * during the machine pre-creation.
2755 ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2756 if (!ADS_ERR_OK(ads_status)) {
2757 libnet_join_set_error_string(mem_ctx, r,
2758 "failed to connect to AD: %s",
2759 ads_errstr(ads_status));
2760 return WERR_NERR_DEFAULTJOINREQUIRED;
2763 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2764 if (ADS_ERR_OK(ads_status)) {
2767 * LDAP object creation succeeded.
2769 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2774 if (initial_account_ou != NULL) {
2775 libnet_join_set_error_string(mem_ctx, r,
2776 "failed to precreate account in ou %s: %s",
2778 ads_errstr(ads_status));
2779 return WERR_NERR_DEFAULTJOINREQUIRED;
2782 DBG_INFO("Failed to pre-create account in OU %s: %s\n",
2783 r->in.account_ou, ads_errstr(ads_status));
2785 #endif /* HAVE_ADS */
2787 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2788 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2789 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2791 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2793 if (!NT_STATUS_IS_OK(status)) {
2794 libnet_join_set_error_string(mem_ctx, r,
2795 "failed to join domain '%s' over rpc: %s",
2796 r->in.domain_name, get_friendly_nt_error_msg(status));
2797 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2798 return WERR_NERR_SETUPALREADYJOINED;
2800 werr = ntstatus_to_werror(status);
2814 /****************************************************************
2815 ****************************************************************/
2817 static WERROR libnet_DomainOfflineJoin(TALLOC_CTX *mem_ctx,
2818 struct libnet_JoinCtx *r)
2822 struct ODJ_WIN7BLOB win7blob;
2823 struct OP_JOINPROV3_PART joinprov3;
2824 const char *dc_name;
2826 if (!r->in.request_offline_join) {
2827 return WERR_NERR_DEFAULTJOINREQUIRED;
2830 if (r->in.odj_provision_data == NULL) {
2831 return WERR_INVALID_PARAMETER;
2834 werr = libnet_odj_find_win7blob(r->in.odj_provision_data, &win7blob);
2835 if (!W_ERROR_IS_OK(werr)) {
2839 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
2840 win7blob.DnsDomainInfo.Name.string);
2841 W_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
2843 r->out.dns_domain_name = talloc_strdup(mem_ctx,
2844 win7blob.DnsDomainInfo.DnsDomainName.string);
2845 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2847 r->out.forest_name = talloc_strdup(mem_ctx,
2848 win7blob.DnsDomainInfo.DnsForestName.string);
2849 W_ERROR_HAVE_NO_MEMORY(r->out.forest_name);
2851 r->out.domain_guid = win7blob.DnsDomainInfo.DomainGuid;
2852 r->out.domain_sid = dom_sid_dup(mem_ctx,
2853 win7blob.DnsDomainInfo.Sid);
2854 W_ERROR_HAVE_NO_MEMORY(r->out.domain_sid);
2856 werr = libnet_odj_find_joinprov3(r->in.odj_provision_data, &joinprov3);
2857 if (!W_ERROR_IS_OK(werr)) {
2861 r->out.account_rid = joinprov3.Rid;
2863 dc_name = strip_hostname(win7blob.DcInfo.dc_address);
2864 if (dc_name == NULL) {
2865 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
2867 r->in.dc_name = talloc_strdup(mem_ctx, dc_name);
2868 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2870 r->out.domain_is_ad = true;
2872 /* we cannot use talloc_steal but have to deep copy the struct here */
2873 status = copy_netr_DsRGetDCNameInfo(mem_ctx, &win7blob.DcInfo,
2875 if (!NT_STATUS_IS_OK(status)) {
2876 return ntstatus_to_werror(status);
2879 werr = libnet_join_check_config(mem_ctx, r);
2880 if (!W_ERROR_IS_OK(werr)) {
2886 /* the following fields are currently not filled in */
2889 uint32_t set_encryption_types;
2890 const char * krb5_salt;
2894 /****************************************************************
2895 ****************************************************************/
2897 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2898 struct libnet_JoinCtx *r)
2901 struct libnet_UnjoinCtx *u = NULL;
2903 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2904 if (!W_ERROR_IS_OK(werr)) {
2908 u->in.debug = r->in.debug;
2909 u->in.dc_name = r->in.dc_name;
2910 u->in.domain_name = r->in.domain_name;
2911 u->in.admin_credentials = r->in.admin_credentials;
2912 u->in.modify_config = r->in.modify_config;
2913 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2914 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2916 werr = libnet_Unjoin(mem_ctx, u);
2922 /****************************************************************
2923 ****************************************************************/
2925 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2926 struct libnet_JoinCtx *r)
2931 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2934 ZERO_STRUCT(r->out);
2936 werr = libnet_join_pre_processing(mem_ctx, r);
2937 if (!W_ERROR_IS_OK(werr)) {
2941 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2942 if (r->in.request_offline_join) {
2943 werr = libnet_DomainOfflineJoin(mem_ctx, r);
2945 werr = libnet_DomainJoin(mem_ctx, r);
2947 if (!W_ERROR_IS_OK(werr)) {
2952 werr = libnet_join_post_processing(mem_ctx, r);
2953 if (!W_ERROR_IS_OK(werr)) {
2957 if (r->in.provision_computer_account_only) {
2959 * When we only provision a computer account we are done here - gd.
2964 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2965 if (r->in.request_offline_join) {
2967 * When we are serving an offline domain join request we
2968 * have no network so we are done here - gd.
2973 werr = libnet_join_post_verify(mem_ctx, r);
2974 if (!W_ERROR_IS_OK(werr)) {
2975 libnet_join_rollback(mem_ctx, r);
2980 r->out.result = werr;
2983 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2988 /****************************************************************
2989 ****************************************************************/
2991 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2992 struct libnet_UnjoinCtx *r)
2996 if (!r->in.domain_sid) {
2998 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2999 libnet_unjoin_set_error_string(mem_ctx, r,
3000 "Unable to fetch domain sid: are we joined?");
3001 return WERR_NERR_SETUPNOTJOINED;
3003 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
3004 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
3007 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
3008 !r->in.delete_machine_account) {
3009 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3013 if (!r->in.dc_name) {
3014 struct netr_DsRGetDCNameInfo *info;
3016 status = dsgetdcname(mem_ctx,
3021 DS_DIRECTORY_SERVICE_REQUIRED |
3022 DS_WRITABLE_REQUIRED |
3025 if (!NT_STATUS_IS_OK(status)) {
3026 libnet_unjoin_set_error_string(mem_ctx, r,
3027 "failed to find DC for domain %s - %s",
3029 get_friendly_nt_error_msg(status));
3030 return WERR_NERR_DCNOTFOUND;
3033 dc = strip_hostname(info->dc_unc);
3034 r->in.dc_name = talloc_strdup(mem_ctx, dc);
3035 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
3039 /* for net ads leave, try to delete the account. If it works,
3040 no sense in disabling. If it fails, we can still try to
3043 if (r->in.delete_machine_account) {
3044 ADS_STATUS ads_status;
3045 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
3046 if (ADS_ERR_OK(ads_status)) {
3048 r->out.dns_domain_name =
3049 talloc_strdup(mem_ctx,
3050 r->in.ads->server.realm);
3052 libnet_unjoin_remove_machine_acct(mem_ctx, r);
3054 if (!ADS_ERR_OK(ads_status)) {
3055 libnet_unjoin_set_error_string(mem_ctx, r,
3056 "failed to remove machine account from AD: %s",
3057 ads_errstr(ads_status));
3059 r->out.deleted_machine_account = true;
3060 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
3061 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3065 #endif /* HAVE_ADS */
3067 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
3069 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
3070 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
3071 if (!NT_STATUS_IS_OK(status)) {
3072 libnet_unjoin_set_error_string(mem_ctx, r,
3073 "failed to disable machine account via rpc: %s",
3074 get_friendly_nt_error_msg(status));
3075 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
3076 return WERR_NERR_SETUPNOTJOINED;
3078 return ntstatus_to_werror(status);
3081 r->out.dns_domain_name = talloc_strdup(mem_ctx,
3083 r->out.disabled_machine_account = true;
3086 /* If disable succeeded or was not requested at all, we
3087 should be getting rid of our end of things */
3089 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
3094 /****************************************************************
3095 ****************************************************************/
3097 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
3098 struct libnet_UnjoinCtx *r)
3100 if (!r->in.domain_name) {
3101 libnet_unjoin_set_error_string(mem_ctx, r,
3102 "No domain name defined");
3103 return WERR_INVALID_PARAMETER;
3106 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
3109 libnet_unjoin_set_error_string(mem_ctx, r,
3110 "Failed to parse domain name");
3111 return WERR_INVALID_PARAMETER;
3115 return WERR_NERR_SETUPDOMAINCONTROLLER;
3118 if (!secrets_init()) {
3119 libnet_unjoin_set_error_string(mem_ctx, r,
3120 "Unable to open secrets database");
3121 return WERR_CAN_NOT_COMPLETE;
3127 /****************************************************************
3128 ****************************************************************/
3130 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
3131 struct libnet_UnjoinCtx *r)
3133 saf_delete(r->out.netbios_domain_name);
3134 saf_delete(r->out.dns_domain_name);
3136 return libnet_unjoin_config(r);
3139 /****************************************************************
3140 ****************************************************************/
3142 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
3143 struct libnet_UnjoinCtx *r)
3148 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
3151 werr = libnet_unjoin_pre_processing(mem_ctx, r);
3152 if (!W_ERROR_IS_OK(werr)) {
3156 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
3157 werr = libnet_DomainUnjoin(mem_ctx, r);
3158 if (!W_ERROR_IS_OK(werr)) {
3159 libnet_unjoin_config(r);
3164 werr = libnet_unjoin_post_processing(mem_ctx, r);
3165 if (!W_ERROR_IS_OK(werr)) {
3170 r->out.result = werr;
3173 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);