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"
47 #include "libsmb/dsgetdcname.h"
49 /****************************************************************
50 ****************************************************************/
52 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
55 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
56 DEBUG(1,("libnet_Join:\n%s", str)); \
60 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
61 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
62 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
63 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
65 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
68 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
69 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
73 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
74 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
75 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
76 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
78 /****************************************************************
79 ****************************************************************/
81 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
82 struct libnet_JoinCtx *r,
83 const char *format, ...)
84 PRINTF_ATTRIBUTE(3,4);
86 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
87 struct libnet_JoinCtx *r,
88 const char *format, ...)
92 if (r->out.error_string) {
96 va_start(args, format);
97 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
101 /****************************************************************
102 ****************************************************************/
104 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
105 struct libnet_UnjoinCtx *r,
106 const char *format, ...)
107 PRINTF_ATTRIBUTE(3,4);
109 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
110 struct libnet_UnjoinCtx *r,
111 const char *format, ...)
115 if (r->out.error_string) {
119 va_start(args, format);
120 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
126 /****************************************************************
127 ****************************************************************/
129 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
130 const char *netbios_domain_name,
132 const char *user_name,
133 const char *password,
138 ADS_STRUCT *my_ads = NULL;
141 my_ads = ads_init(dns_domain_name,
145 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
149 SAFE_FREE(my_ads->auth.user_name);
150 my_ads->auth.user_name = SMB_STRDUP(user_name);
151 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
153 SAFE_FREE(my_ads->auth.realm);
154 my_ads->auth.realm = smb_xstrdup(cp);
155 if (!strupper_m(my_ads->auth.realm)) {
156 ads_destroy(&my_ads);
157 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
163 SAFE_FREE(my_ads->auth.password);
164 my_ads->auth.password = SMB_STRDUP(password);
167 if (ccname != NULL) {
168 SAFE_FREE(my_ads->auth.ccache_name);
169 my_ads->auth.ccache_name = SMB_STRDUP(ccname);
170 setenv(KRB5_ENV_CCNAME, my_ads->auth.ccache_name, 1);
173 status = ads_connect_user_creds(my_ads);
174 if (!ADS_ERR_OK(status)) {
175 ads_destroy(&my_ads);
183 /****************************************************************
184 ****************************************************************/
186 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
187 struct libnet_JoinCtx *r,
188 bool use_machine_creds)
191 const char *username;
192 const char *password;
193 const char *ccname = NULL;
195 if (use_machine_creds) {
196 if (r->in.machine_name == NULL ||
197 r->in.machine_password == NULL) {
198 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
200 username = talloc_asprintf(mem_ctx, "%s$",
202 if (username == NULL) {
203 return ADS_ERROR(LDAP_NO_MEMORY);
205 password = r->in.machine_password;
206 ccname = "MEMORY:libnet_join_machine_creds";
210 username = r->in.admin_account;
212 p = strchr(r->in.admin_account, '@');
214 username = talloc_asprintf(mem_ctx, "%s@%s",
218 if (username == NULL) {
219 return ADS_ERROR(LDAP_NO_MEMORY);
221 password = r->in.admin_password;
224 * when r->in.use_kerberos is set to allow "net ads join -k" we
225 * may not override the provided credential cache - gd
228 if (!r->in.use_kerberos) {
229 ccname = "MEMORY:libnet_join_user_creds";
233 status = libnet_connect_ads(r->out.dns_domain_name,
234 r->out.netbios_domain_name,
240 if (!ADS_ERR_OK(status)) {
241 libnet_join_set_error_string(mem_ctx, r,
242 "failed to connect to AD: %s",
247 if (!r->out.netbios_domain_name) {
248 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
249 r->in.ads->server.workgroup);
250 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
253 if (!r->out.dns_domain_name) {
254 r->out.dns_domain_name = talloc_strdup(mem_ctx,
255 r->in.ads->config.realm);
256 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
259 r->out.domain_is_ad = true;
264 /****************************************************************
265 ****************************************************************/
267 static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
268 struct libnet_JoinCtx *r)
270 return libnet_join_connect_ads(mem_ctx, r, false);
273 /****************************************************************
274 ****************************************************************/
276 static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
277 struct libnet_JoinCtx *r)
279 return libnet_join_connect_ads(mem_ctx, r, true);
282 /****************************************************************
283 ****************************************************************/
285 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
286 struct libnet_UnjoinCtx *r)
290 status = libnet_connect_ads(r->in.domain_name,
294 r->in.admin_password,
297 if (!ADS_ERR_OK(status)) {
298 libnet_unjoin_set_error_string(mem_ctx, r,
299 "failed to connect to AD: %s",
306 /****************************************************************
307 join a domain using ADS (LDAP mods)
308 ****************************************************************/
310 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
311 struct libnet_JoinCtx *r)
314 LDAPMessage *res = NULL;
315 const char *attrs[] = { "dn", NULL };
318 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
319 if (!ADS_ERR_OK(status)) {
323 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
324 if (!ADS_ERR_OK(status)) {
328 if (ads_count_replies(r->in.ads, res) != 1) {
329 ads_msgfree(r->in.ads, res);
330 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
333 ads_msgfree(r->in.ads, res);
335 /* Attempt to create the machine account and bail if this fails.
336 Assume that the admin wants exactly what they requested */
338 status = ads_create_machine_acct(r->in.ads,
341 r->in.desired_encryption_types);
343 if (ADS_ERR_OK(status)) {
344 DEBUG(1,("machine account creation created\n"));
346 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
347 (status.err.rc == LDAP_ALREADY_EXISTS)) {
348 status = ADS_SUCCESS;
351 if (!ADS_ERR_OK(status)) {
352 DEBUG(1,("machine account creation failed\n"));
356 status = ads_move_machine_acct(r->in.ads,
360 if (!ADS_ERR_OK(status)) {
361 DEBUG(1,("failure to locate/move pre-existing "
362 "machine account\n"));
366 DEBUG(1,("The machine account %s the specified OU.\n",
367 moved ? "was moved into" : "already exists in"));
372 /****************************************************************
373 ****************************************************************/
375 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
376 struct libnet_UnjoinCtx *r)
381 status = libnet_unjoin_connect_ads(mem_ctx, r);
382 if (!ADS_ERR_OK(status)) {
383 libnet_unjoin_set_error_string(mem_ctx, r,
384 "failed to connect to AD: %s",
390 status = ads_leave_realm(r->in.ads, r->in.machine_name);
391 if (!ADS_ERR_OK(status)) {
392 libnet_unjoin_set_error_string(mem_ctx, r,
393 "failed to leave realm: %s",
401 /****************************************************************
402 ****************************************************************/
404 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
405 struct libnet_JoinCtx *r)
408 LDAPMessage *res = NULL;
411 if (!r->in.machine_name) {
412 return ADS_ERROR(LDAP_NO_MEMORY);
415 status = ads_find_machine_acct(r->in.ads,
418 if (!ADS_ERR_OK(status)) {
422 if (ads_count_replies(r->in.ads, res) != 1) {
423 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
427 dn = ads_get_dn(r->in.ads, mem_ctx, res);
429 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
433 r->out.dn = talloc_strdup(mem_ctx, dn);
435 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
439 if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
440 &r->out.set_encryption_types)) {
441 r->out.set_encryption_types = 0;
445 ads_msgfree(r->in.ads, res);
451 static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx,
452 struct libnet_JoinCtx *r,
458 if (r->in.machine_name == NULL) {
459 return ADS_ERROR_SYSTEM(EINVAL);
462 status = ads_get_service_principal_names(mem_ctx,
471 /****************************************************************
472 Set a machines dNSHostName and servicePrincipalName attributes
473 ****************************************************************/
475 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
476 struct libnet_JoinCtx *r)
481 const char **spn_array = NULL;
485 const char **netbios_aliases = NULL;
489 status = libnet_join_find_machine_acct(mem_ctx, r);
490 if (!ADS_ERR_OK(status)) {
494 status = libnet_join_get_machine_spns(mem_ctx,
496 discard_const_p(char **, &spn_array),
498 if (!ADS_ERR_OK(status)) {
499 DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
502 /* Windows only creates HOST/shortname & HOST/fqdn. */
504 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
506 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
508 if (!strupper_m(spn)) {
509 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
512 ok = ads_element_in_array(spn_array, num_spns, spn);
514 ok = add_string_to_array(spn_array, spn,
515 &spn_array, &num_spns);
517 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
521 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
522 || (strchr(my_fqdn, '.') == NULL)) {
523 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
524 r->out.dns_domain_name);
527 if (!strlower_m(my_fqdn)) {
528 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
531 if (!strequal(my_fqdn, r->in.machine_name)) {
532 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
534 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
537 ok = ads_element_in_array(spn_array, num_spns, spn);
539 ok = add_string_to_array(spn_array, spn,
540 &spn_array, &num_spns);
542 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
547 netbios_aliases = lp_netbios_aliases();
548 if (netbios_aliases != NULL) {
549 for (; *netbios_aliases != NULL; netbios_aliases++) {
551 * Add HOST/NETBIOSNAME
553 spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases);
556 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
558 if (!strupper_m(spn)) {
560 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
563 ok = ads_element_in_array(spn_array, num_spns, spn);
568 ok = add_string_to_array(spn_array, spn,
569 &spn_array, &num_spns);
572 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
577 * Add HOST/netbiosname.domainname
579 if (r->out.dns_domain_name == NULL) {
582 fstr_sprintf(my_fqdn, "%s.%s",
584 r->out.dns_domain_name);
586 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
588 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
591 ok = ads_element_in_array(spn_array, num_spns, spn);
596 ok = add_string_to_array(spn_array, spn,
597 &spn_array, &num_spns);
600 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
606 /* make sure to NULL terminate the array */
607 spn_array = talloc_realloc(mem_ctx, spn_array, const char *, num_spns + 1);
608 if (spn_array == NULL) {
609 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
611 spn_array[num_spns] = NULL;
613 mods = ads_init_mods(mem_ctx);
615 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
618 /* fields of primary importance */
620 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
621 if (!ADS_ERR_OK(status)) {
622 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
625 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
627 if (!ADS_ERR_OK(status)) {
628 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
631 return ads_gen_mod(r->in.ads, r->out.dn, mods);
634 /****************************************************************
635 ****************************************************************/
637 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
638 struct libnet_JoinCtx *r)
643 if (!r->in.create_upn) {
649 status = libnet_join_find_machine_acct(mem_ctx, r);
650 if (!ADS_ERR_OK(status)) {
655 const char *realm = r->out.dns_domain_name;
657 /* in case we are about to generate a keytab during the join
658 * make sure the default upn we create is usable with kinit -k.
661 if (USE_KERBEROS_KEYTAB) {
662 realm = talloc_strdup_upper(mem_ctx,
663 r->out.dns_domain_name);
667 return ADS_ERROR(LDAP_NO_MEMORY);
670 r->in.upn = talloc_asprintf(mem_ctx,
675 return ADS_ERROR(LDAP_NO_MEMORY);
679 /* now do the mods */
681 mods = ads_init_mods(mem_ctx);
683 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
686 /* fields of primary importance */
688 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
689 if (!ADS_ERR_OK(status)) {
690 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
693 return ads_gen_mod(r->in.ads, r->out.dn, mods);
697 /****************************************************************
698 ****************************************************************/
700 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
701 struct libnet_JoinCtx *r)
707 if (!r->in.os_name || !r->in.os_version ) {
713 status = libnet_join_find_machine_acct(mem_ctx, r);
714 if (!ADS_ERR_OK(status)) {
718 /* now do the mods */
720 mods = ads_init_mods(mem_ctx);
722 return ADS_ERROR(LDAP_NO_MEMORY);
725 if (r->in.os_servicepack) {
727 * if blank string then leave os_sp equal to NULL to force
728 * attribute delete (LDAP_MOD_DELETE)
730 if (!strequal(r->in.os_servicepack,"")) {
731 os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
734 os_sp = talloc_asprintf(mem_ctx, "Samba %s",
735 samba_version_string());
737 if (!os_sp && !strequal(r->in.os_servicepack,"")) {
738 return ADS_ERROR(LDAP_NO_MEMORY);
741 /* fields of primary importance */
743 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
745 if (!ADS_ERR_OK(status)) {
749 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
751 if (!ADS_ERR_OK(status)) {
755 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
757 if (!ADS_ERR_OK(status)) {
761 return ads_gen_mod(r->in.ads, r->out.dn, mods);
764 /****************************************************************
765 ****************************************************************/
767 static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
768 struct libnet_JoinCtx *r)
772 const char *etype_list_str;
774 etype_list_str = talloc_asprintf(mem_ctx, "%d",
775 r->in.desired_encryption_types);
776 if (!etype_list_str) {
777 return ADS_ERROR(LDAP_NO_MEMORY);
782 status = libnet_join_find_machine_acct(mem_ctx, r);
783 if (!ADS_ERR_OK(status)) {
787 if (r->in.desired_encryption_types == r->out.set_encryption_types) {
791 /* now do the mods */
793 mods = ads_init_mods(mem_ctx);
795 return ADS_ERROR(LDAP_NO_MEMORY);
798 status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
800 if (!ADS_ERR_OK(status)) {
804 status = ads_gen_mod(r->in.ads, r->out.dn, mods);
805 if (!ADS_ERR_OK(status)) {
809 r->out.set_encryption_types = r->in.desired_encryption_types;
814 /****************************************************************
815 ****************************************************************/
817 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
818 struct libnet_JoinCtx *r)
820 if (!USE_SYSTEM_KEYTAB) {
824 if (ads_keytab_create_default(r->in.ads) != 0) {
831 /****************************************************************
832 ****************************************************************/
834 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
835 struct libnet_JoinCtx *r)
837 uint32_t domain_func;
839 const char *salt = NULL;
840 char *std_salt = NULL;
842 status = ads_domain_func_level(r->in.ads, &domain_func);
843 if (!ADS_ERR_OK(status)) {
844 libnet_join_set_error_string(mem_ctx, r,
845 "failed to determine domain functional level: %s",
850 /* go ahead and setup the default salt */
852 std_salt = kerberos_standard_des_salt();
854 libnet_join_set_error_string(mem_ctx, r,
855 "failed to obtain standard DES salt");
859 salt = talloc_strdup(mem_ctx, std_salt);
866 /* if it's a Windows functional domain, we have to look for the UPN */
868 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
871 upn = ads_get_upn(r->in.ads, mem_ctx,
874 salt = talloc_strdup(mem_ctx, upn);
881 r->out.krb5_salt = salt;
885 /****************************************************************
886 ****************************************************************/
888 static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
889 struct libnet_JoinCtx *r)
892 bool need_etype_update = false;
895 status = libnet_join_connect_ads_user(mem_ctx, r);
896 if (!ADS_ERR_OK(status)) {
901 status = libnet_join_set_machine_spn(mem_ctx, r);
902 if (!ADS_ERR_OK(status)) {
903 libnet_join_set_error_string(mem_ctx, r,
904 "Failed to set machine spn: %s\n"
905 "Do you have sufficient permissions to create machine "
911 status = libnet_join_set_os_attributes(mem_ctx, r);
912 if (!ADS_ERR_OK(status)) {
913 libnet_join_set_error_string(mem_ctx, r,
914 "failed to set machine os attributes: %s",
919 status = libnet_join_set_machine_upn(mem_ctx, r);
920 if (!ADS_ERR_OK(status)) {
921 libnet_join_set_error_string(mem_ctx, r,
922 "failed to set machine upn: %s",
927 status = libnet_join_find_machine_acct(mem_ctx, r);
928 if (!ADS_ERR_OK(status)) {
932 if (r->in.desired_encryption_types != r->out.set_encryption_types) {
933 uint32_t func_level = 0;
935 status = ads_domain_func_level(r->in.ads, &func_level);
936 if (!ADS_ERR_OK(status)) {
937 libnet_join_set_error_string(mem_ctx, r,
938 "failed to query domain controller functional level: %s",
943 if (func_level >= DS_DOMAIN_FUNCTION_2008) {
944 need_etype_update = true;
948 if (need_etype_update) {
950 * We need to reconnect as machine account in order
951 * to update msDS-SupportedEncryptionTypes reliable
954 if (r->in.ads->auth.ccache_name != NULL) {
955 ads_kdestroy(r->in.ads->auth.ccache_name);
958 ads_destroy(&r->in.ads);
960 status = libnet_join_connect_ads_machine(mem_ctx, r);
961 if (!ADS_ERR_OK(status)) {
962 libnet_join_set_error_string(mem_ctx, r,
963 "Failed to connect as machine account: %s",
968 status = libnet_join_set_etypes(mem_ctx, r);
969 if (!ADS_ERR_OK(status)) {
970 libnet_join_set_error_string(mem_ctx, r,
971 "failed to set machine kerberos encryption types: %s",
977 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
978 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
984 static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
985 struct libnet_JoinCtx *r)
987 if (!libnet_join_create_keytab(mem_ctx, r)) {
988 libnet_join_set_error_string(mem_ctx, r,
989 "failed to create kerberos keytab");
990 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
995 #endif /* HAVE_ADS */
997 /****************************************************************
998 Store the machine password and domain SID
999 ****************************************************************/
1001 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
1002 struct libnet_JoinCtx *r)
1006 status = secrets_store_JoinCtx(r);
1007 if (!NT_STATUS_IS_OK(status)) {
1008 DBG_ERR("secrets_store_JoinCtx() failed %s\n",
1016 /****************************************************************
1017 Connect dc's IPC$ share
1018 ****************************************************************/
1020 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
1025 struct cli_state **cli)
1030 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1033 if (use_kerberos && pass) {
1034 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
1037 return cli_full_connection(cli, NULL,
1045 SMB_SIGNING_IPC_DEFAULT);
1048 /****************************************************************
1049 Lookup domain dc's info
1050 ****************************************************************/
1052 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1053 struct libnet_JoinCtx *r,
1054 struct cli_state **cli)
1056 struct rpc_pipe_client *pipe_hnd = NULL;
1057 struct policy_handle lsa_pol;
1058 NTSTATUS status, result;
1059 union lsa_PolicyInformation *info = NULL;
1060 struct dcerpc_binding_handle *b;
1061 const char *account = r->in.admin_account;
1062 const char *domain = r->in.admin_domain;
1063 const char *password = r->in.admin_password;
1064 bool use_kerberos = r->in.use_kerberos;
1066 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
1070 use_kerberos = false;
1073 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1079 if (!NT_STATUS_IS_OK(status)) {
1083 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1085 if (!NT_STATUS_IS_OK(status)) {
1086 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
1087 nt_errstr(status)));
1091 b = pipe_hnd->binding_handle;
1093 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1094 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1095 if (!NT_STATUS_IS_OK(status)) {
1099 status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1101 LSA_POLICY_INFO_DNS,
1104 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1105 r->out.domain_is_ad = true;
1106 r->out.netbios_domain_name = info->dns.name.string;
1107 r->out.dns_domain_name = info->dns.dns_domain.string;
1108 r->out.forest_name = info->dns.dns_forest.string;
1109 r->out.domain_guid = info->dns.domain_guid;
1110 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1111 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1114 if (!NT_STATUS_IS_OK(status)) {
1115 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1117 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1120 if (!NT_STATUS_IS_OK(status)) {
1123 if (!NT_STATUS_IS_OK(result)) {
1128 r->out.netbios_domain_name = info->account_domain.name.string;
1129 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1130 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1133 dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1134 TALLOC_FREE(pipe_hnd);
1140 /****************************************************************
1141 Do the domain join unsecure
1142 ****************************************************************/
1144 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1145 struct libnet_JoinCtx *r,
1146 struct cli_state *cli)
1148 TALLOC_CTX *frame = talloc_stackframe();
1149 struct rpc_pipe_client *authenticate_pipe = NULL;
1150 struct rpc_pipe_client *passwordset_pipe = NULL;
1151 struct cli_credentials *cli_creds;
1152 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1153 struct netlogon_creds_CredentialState *creds = NULL;
1154 uint32_t netlogon_flags = 0;
1157 DATA_BLOB new_trust_blob = data_blob_null;
1160 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
1161 &authenticate_pipe);
1162 if (!NT_STATUS_IS_OK(status)) {
1167 if (!r->in.machine_password) {
1168 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1170 r->in.machine_password = trust_pw_new_value(mem_ctx,
1171 r->in.secure_channel_type,
1173 if (r->in.machine_password == NULL) {
1175 return NT_STATUS_NO_MEMORY;
1179 cli_creds = cli_credentials_init(talloc_tos());
1180 if (cli_creds == NULL) {
1182 return NT_STATUS_NO_MEMORY;
1185 cli_credentials_set_username(cli_creds, r->out.account_name,
1187 cli_credentials_set_domain(cli_creds, r->in.domain_name,
1189 cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
1190 cli_credentials_set_secure_channel_type(cli_creds,
1191 r->in.secure_channel_type);
1193 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
1194 cli_credentials_set_password(cli_creds, r->in.admin_password,
1197 status = rpccli_create_netlogon_creds_ctx(
1198 cli_creds, authenticate_pipe->desthost, r->in.msg_ctx,
1199 frame, &netlogon_creds);
1200 if (!NT_STATUS_IS_OK(status)) {
1205 status = rpccli_setup_netlogon_creds(
1206 cli, NCACN_NP, netlogon_creds, true /* force_reauth */,
1208 if (!NT_STATUS_IS_OK(status)) {
1213 status = netlogon_creds_cli_get(netlogon_creds, frame, &creds);
1214 if (!NT_STATUS_IS_OK(status)) {
1219 netlogon_flags = creds->negotiate_flags;
1222 if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
1223 status = cli_rpc_pipe_open_schannel_with_creds(cli,
1224 &ndr_table_netlogon,
1228 if (!NT_STATUS_IS_OK(status)) {
1233 passwordset_pipe = authenticate_pipe;
1236 len = strlen(r->in.machine_password);
1237 ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
1238 r->in.machine_password, len,
1239 (void **)&new_trust_blob.data,
1240 &new_trust_blob.length);
1242 status = NT_STATUS_UNMAPPABLE_CHARACTER;
1243 if (errno == ENOMEM) {
1244 status = NT_STATUS_NO_MEMORY;
1250 status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1251 passwordset_pipe->binding_handle,
1253 NULL); /* new_version */
1254 if (!NT_STATUS_IS_OK(status)) {
1260 return NT_STATUS_OK;
1263 /****************************************************************
1265 ****************************************************************/
1267 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1268 struct libnet_JoinCtx *r,
1269 struct cli_state *cli)
1271 struct rpc_pipe_client *pipe_hnd = NULL;
1272 struct policy_handle sam_pol, domain_pol, user_pol;
1273 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1275 struct lsa_String lsa_acct_name;
1277 uint32_t acct_flags = ACB_WSTRUST;
1278 struct samr_Ids user_rids;
1279 struct samr_Ids name_types;
1280 union samr_UserInfo user_info;
1281 struct dcerpc_binding_handle *b = NULL;
1282 unsigned int old_timeout = 0;
1284 DATA_BLOB session_key = data_blob_null;
1285 struct samr_CryptPassword crypt_pwd;
1286 struct samr_CryptPasswordEx crypt_pwd_ex;
1288 ZERO_STRUCT(sam_pol);
1289 ZERO_STRUCT(domain_pol);
1290 ZERO_STRUCT(user_pol);
1292 switch (r->in.secure_channel_type) {
1293 case SEC_CHAN_WKSTA:
1294 acct_flags = ACB_WSTRUST;
1297 acct_flags = ACB_SVRTRUST;
1300 return NT_STATUS_INVALID_PARAMETER;
1303 if (!r->in.machine_password) {
1304 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1306 r->in.machine_password = trust_pw_new_value(mem_ctx,
1307 r->in.secure_channel_type,
1309 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1312 /* Open the domain */
1314 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1316 if (!NT_STATUS_IS_OK(status)) {
1317 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1318 nt_errstr(status)));
1322 b = pipe_hnd->binding_handle;
1324 status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1325 if (!NT_STATUS_IS_OK(status)) {
1326 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1327 nt_errstr(status)));
1331 status = dcerpc_samr_Connect2(b, mem_ctx,
1333 SAMR_ACCESS_ENUM_DOMAINS
1334 | SAMR_ACCESS_LOOKUP_DOMAIN,
1337 if (!NT_STATUS_IS_OK(status)) {
1340 if (!NT_STATUS_IS_OK(result)) {
1345 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1347 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1348 | SAMR_DOMAIN_ACCESS_CREATE_USER
1349 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1353 if (!NT_STATUS_IS_OK(status)) {
1356 if (!NT_STATUS_IS_OK(result)) {
1361 /* Create domain user */
1363 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1364 if (!strlower_m(acct_name)) {
1365 status = NT_STATUS_INVALID_PARAMETER;
1369 init_lsa_String(&lsa_acct_name, acct_name);
1371 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1372 uint32_t access_desired =
1373 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1374 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1375 SAMR_USER_ACCESS_SET_PASSWORD |
1376 SAMR_USER_ACCESS_GET_ATTRIBUTES |
1377 SAMR_USER_ACCESS_SET_ATTRIBUTES;
1378 uint32_t access_granted = 0;
1380 DEBUG(10,("Creating account with desired access mask: %d\n",
1383 status = dcerpc_samr_CreateUser2(b, mem_ctx,
1392 if (!NT_STATUS_IS_OK(status)) {
1397 if (!NT_STATUS_IS_OK(status) &&
1398 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1400 DEBUG(10,("Creation of workstation account failed: %s\n",
1401 nt_errstr(status)));
1403 /* If NT_STATUS_ACCESS_DENIED then we have a valid
1404 username/password combo but the user does not have
1405 administrator access. */
1407 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1408 libnet_join_set_error_string(mem_ctx, r,
1409 "User specified does not have "
1410 "administrator privileges");
1416 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1417 if (!(r->in.join_flags &
1418 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1423 /* We *must* do this.... don't ask... */
1425 if (NT_STATUS_IS_OK(status)) {
1426 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1430 status = dcerpc_samr_LookupNames(b, mem_ctx,
1437 if (!NT_STATUS_IS_OK(status)) {
1440 if (!NT_STATUS_IS_OK(result)) {
1444 if (user_rids.count != 1) {
1445 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1448 if (name_types.count != 1) {
1449 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1453 if (name_types.ids[0] != SID_NAME_USER) {
1454 DEBUG(0,("%s is not a user account (type=%d)\n",
1455 acct_name, name_types.ids[0]));
1456 status = NT_STATUS_INVALID_WORKSTATION;
1460 user_rid = user_rids.ids[0];
1462 /* Open handle on user */
1464 status = dcerpc_samr_OpenUser(b, mem_ctx,
1466 SEC_FLAG_MAXIMUM_ALLOWED,
1470 if (!NT_STATUS_IS_OK(status)) {
1473 if (!NT_STATUS_IS_OK(result)) {
1478 /* Fill in the additional account flags now */
1480 acct_flags |= ACB_PWNOEXP;
1482 /* Set account flags on machine account */
1483 ZERO_STRUCT(user_info.info16);
1484 user_info.info16.acct_flags = acct_flags;
1486 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1488 UserControlInformation,
1491 if (!NT_STATUS_IS_OK(status)) {
1492 dcerpc_samr_DeleteUser(b, mem_ctx,
1496 libnet_join_set_error_string(mem_ctx, r,
1497 "Failed to set account flags for machine account (%s)\n",
1502 if (!NT_STATUS_IS_OK(result)) {
1505 dcerpc_samr_DeleteUser(b, mem_ctx,
1509 libnet_join_set_error_string(mem_ctx, r,
1510 "Failed to set account flags for machine account (%s)\n",
1515 /* Set password on machine account - first try level 26 */
1518 * increase the timeout as password filter modules on the DC
1519 * might delay the operation for a significant amount of time
1521 old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1523 init_samr_CryptPasswordEx(r->in.machine_password,
1527 user_info.info26.password = crypt_pwd_ex;
1528 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1530 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1532 UserInternal5InformationNew,
1536 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1538 /* retry with level 24 */
1540 init_samr_CryptPassword(r->in.machine_password,
1544 user_info.info24.password = crypt_pwd;
1545 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1547 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1549 UserInternal5Information,
1554 old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1556 if (!NT_STATUS_IS_OK(status)) {
1558 dcerpc_samr_DeleteUser(b, mem_ctx,
1562 libnet_join_set_error_string(mem_ctx, r,
1563 "Failed to set password for machine account (%s)\n",
1567 if (!NT_STATUS_IS_OK(result)) {
1570 dcerpc_samr_DeleteUser(b, mem_ctx,
1574 libnet_join_set_error_string(mem_ctx, r,
1575 "Failed to set password for machine account (%s)\n",
1580 status = NT_STATUS_OK;
1587 data_blob_clear_free(&session_key);
1589 if (is_valid_policy_hnd(&sam_pol)) {
1590 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1592 if (is_valid_policy_hnd(&domain_pol)) {
1593 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1595 if (is_valid_policy_hnd(&user_pol)) {
1596 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1598 TALLOC_FREE(pipe_hnd);
1603 /****************************************************************
1604 ****************************************************************/
1606 NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1607 const char *netbios_domain_name,
1608 const char *dc_name,
1609 const bool use_kerberos)
1611 TALLOC_CTX *frame = talloc_stackframe();
1612 struct cli_state *cli = NULL;
1613 struct rpc_pipe_client *netlogon_pipe = NULL;
1614 struct cli_credentials *cli_creds = NULL;
1615 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1616 struct netlogon_creds_CredentialState *creds = NULL;
1617 uint32_t netlogon_flags = 0;
1623 return NT_STATUS_INVALID_PARAMETER;
1626 if (!secrets_init()) {
1628 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1631 status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1633 if (!NT_STATUS_IS_OK(status)) {
1638 /* we don't want any old password */
1639 cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1642 cli_credentials_set_kerberos_state(cli_creds,
1643 CRED_MUST_USE_KERBEROS);
1646 status = cli_full_connection_creds(&cli, NULL,
1652 SMB_SIGNING_IPC_DEFAULT);
1654 if (!NT_STATUS_IS_OK(status)) {
1655 status = cli_full_connection(&cli, NULL,
1663 SMB_SIGNING_IPC_DEFAULT);
1666 if (!NT_STATUS_IS_OK(status)) {
1671 status = rpccli_create_netlogon_creds_ctx(cli_creds,
1676 if (!NT_STATUS_IS_OK(status)) {
1682 status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
1684 true, /* force_reauth */
1686 if (!NT_STATUS_IS_OK(status)) {
1687 DEBUG(0,("connect_to_domain_password_server: "
1688 "unable to open the domain client session to "
1689 "machine %s. Flags[0x%08X] Error was : %s.\n",
1690 dc_name, (unsigned)netlogon_flags,
1691 nt_errstr(status)));
1697 status = netlogon_creds_cli_get(netlogon_creds,
1700 if (!NT_STATUS_IS_OK(status)) {
1705 netlogon_flags = creds->negotiate_flags;
1708 if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1711 return NT_STATUS_OK;
1714 status = cli_rpc_pipe_open_schannel_with_creds(
1715 cli, &ndr_table_netlogon, NCACN_NP,
1716 netlogon_creds, &netlogon_pipe);
1718 TALLOC_FREE(netlogon_pipe);
1720 if (!NT_STATUS_IS_OK(status)) {
1721 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1722 "on netlogon pipe to server %s for domain %s. "
1724 smbXcli_conn_remote_name(cli->conn),
1725 netbios_domain_name, nt_errstr(status)));
1733 return NT_STATUS_OK;
1736 /****************************************************************
1737 ****************************************************************/
1739 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1740 struct libnet_JoinCtx *r)
1744 status = libnet_join_ok(r->in.msg_ctx,
1745 r->out.netbios_domain_name,
1747 r->in.use_kerberos);
1748 if (!NT_STATUS_IS_OK(status)) {
1749 libnet_join_set_error_string(mem_ctx, r,
1750 "failed to verify domain membership after joining: %s",
1751 get_friendly_nt_error_msg(status));
1752 return WERR_NERR_SETUPNOTJOINED;
1758 /****************************************************************
1759 ****************************************************************/
1761 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1762 struct libnet_UnjoinCtx *r)
1765 * TODO: use values from 'struct libnet_UnjoinCtx' ?
1767 return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
1770 /****************************************************************
1771 ****************************************************************/
1773 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1774 struct libnet_UnjoinCtx *r)
1776 struct cli_state *cli = NULL;
1777 struct rpc_pipe_client *pipe_hnd = NULL;
1778 struct policy_handle sam_pol, domain_pol, user_pol;
1779 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1782 struct lsa_String lsa_acct_name;
1783 struct samr_Ids user_rids;
1784 struct samr_Ids name_types;
1785 union samr_UserInfo *info = NULL;
1786 struct dcerpc_binding_handle *b = NULL;
1788 ZERO_STRUCT(sam_pol);
1789 ZERO_STRUCT(domain_pol);
1790 ZERO_STRUCT(user_pol);
1792 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1793 r->in.admin_account,
1795 r->in.admin_password,
1798 if (!NT_STATUS_IS_OK(status)) {
1802 /* Open the domain */
1804 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1806 if (!NT_STATUS_IS_OK(status)) {
1807 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1808 nt_errstr(status)));
1812 b = pipe_hnd->binding_handle;
1814 status = dcerpc_samr_Connect2(b, mem_ctx,
1816 SEC_FLAG_MAXIMUM_ALLOWED,
1819 if (!NT_STATUS_IS_OK(status)) {
1822 if (!NT_STATUS_IS_OK(result)) {
1827 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1829 SEC_FLAG_MAXIMUM_ALLOWED,
1833 if (!NT_STATUS_IS_OK(status)) {
1836 if (!NT_STATUS_IS_OK(result)) {
1841 /* Create domain user */
1843 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1844 if (!strlower_m(acct_name)) {
1845 status = NT_STATUS_INVALID_PARAMETER;
1849 init_lsa_String(&lsa_acct_name, acct_name);
1851 status = dcerpc_samr_LookupNames(b, mem_ctx,
1859 if (!NT_STATUS_IS_OK(status)) {
1862 if (!NT_STATUS_IS_OK(result)) {
1866 if (user_rids.count != 1) {
1867 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1870 if (name_types.count != 1) {
1871 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1875 if (name_types.ids[0] != SID_NAME_USER) {
1876 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1877 name_types.ids[0]));
1878 status = NT_STATUS_INVALID_WORKSTATION;
1882 user_rid = user_rids.ids[0];
1884 /* Open handle on user */
1886 status = dcerpc_samr_OpenUser(b, mem_ctx,
1888 SEC_FLAG_MAXIMUM_ALLOWED,
1892 if (!NT_STATUS_IS_OK(status)) {
1895 if (!NT_STATUS_IS_OK(result)) {
1902 status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1907 if (!NT_STATUS_IS_OK(status)) {
1908 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1911 if (!NT_STATUS_IS_OK(result)) {
1913 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1917 /* now disable and setuser info */
1919 info->info16.acct_flags |= ACB_DISABLED;
1921 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1926 if (!NT_STATUS_IS_OK(status)) {
1927 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1930 if (!NT_STATUS_IS_OK(result)) {
1932 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1936 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1939 if (pipe_hnd && b) {
1940 if (is_valid_policy_hnd(&domain_pol)) {
1941 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1943 if (is_valid_policy_hnd(&sam_pol)) {
1944 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1946 TALLOC_FREE(pipe_hnd);
1956 /****************************************************************
1957 ****************************************************************/
1959 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1961 WERROR werr = WERR_OK;
1963 struct smbconf_ctx *ctx;
1965 err = smbconf_init_reg(r, &ctx, NULL);
1966 if (!SBC_ERROR_IS_OK(err)) {
1967 werr = WERR_SERVICE_DOES_NOT_EXIST;
1971 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1973 err = smbconf_set_global_parameter(ctx, "security", "user");
1974 if (!SBC_ERROR_IS_OK(err)) {
1975 werr = WERR_SERVICE_DOES_NOT_EXIST;
1979 err = smbconf_set_global_parameter(ctx, "workgroup",
1981 if (!SBC_ERROR_IS_OK(err)) {
1982 werr = WERR_SERVICE_DOES_NOT_EXIST;
1986 smbconf_delete_global_parameter(ctx, "realm");
1990 err = smbconf_set_global_parameter(ctx, "security", "domain");
1991 if (!SBC_ERROR_IS_OK(err)) {
1992 werr = WERR_SERVICE_DOES_NOT_EXIST;
1996 err = smbconf_set_global_parameter(ctx, "workgroup",
1997 r->out.netbios_domain_name);
1998 if (!SBC_ERROR_IS_OK(err)) {
1999 werr = WERR_SERVICE_DOES_NOT_EXIST;
2003 if (r->out.domain_is_ad) {
2004 err = smbconf_set_global_parameter(ctx, "security", "ads");
2005 if (!SBC_ERROR_IS_OK(err)) {
2006 werr = WERR_SERVICE_DOES_NOT_EXIST;
2010 err = smbconf_set_global_parameter(ctx, "realm",
2011 r->out.dns_domain_name);
2012 if (!SBC_ERROR_IS_OK(err)) {
2013 werr = WERR_SERVICE_DOES_NOT_EXIST;
2019 smbconf_shutdown(ctx);
2023 /****************************************************************
2024 ****************************************************************/
2026 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
2028 WERROR werr = WERR_OK;
2030 struct smbconf_ctx *ctx;
2032 err = smbconf_init_reg(r, &ctx, NULL);
2033 if (!SBC_ERROR_IS_OK(err)) {
2034 werr = WERR_SERVICE_DOES_NOT_EXIST;
2038 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2040 err = smbconf_set_global_parameter(ctx, "security", "user");
2041 if (!SBC_ERROR_IS_OK(err)) {
2042 werr = WERR_SERVICE_DOES_NOT_EXIST;
2046 err = smbconf_delete_global_parameter(ctx, "workgroup");
2047 if (!SBC_ERROR_IS_OK(err)) {
2048 werr = WERR_SERVICE_DOES_NOT_EXIST;
2052 smbconf_delete_global_parameter(ctx, "realm");
2056 smbconf_shutdown(ctx);
2060 /****************************************************************
2061 ****************************************************************/
2063 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
2067 if (!W_ERROR_IS_OK(r->out.result)) {
2068 return r->out.result;
2071 if (!r->in.modify_config) {
2075 werr = do_join_modify_vals_config(r);
2076 if (!W_ERROR_IS_OK(werr)) {
2080 lp_load_global(get_dyn_CONFIGFILE());
2082 r->out.modified_config = true;
2083 r->out.result = werr;
2088 /****************************************************************
2089 ****************************************************************/
2091 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2095 if (!W_ERROR_IS_OK(r->out.result)) {
2096 return r->out.result;
2099 if (!r->in.modify_config) {
2103 werr = do_unjoin_modify_vals_config(r);
2104 if (!W_ERROR_IS_OK(werr)) {
2108 lp_load_global(get_dyn_CONFIGFILE());
2110 r->out.modified_config = true;
2111 r->out.result = werr;
2116 /****************************************************************
2117 ****************************************************************/
2119 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
2120 const char *domain_str,
2121 const char **domain_p,
2124 char *domain = NULL;
2126 const char *p = NULL;
2128 if (!domain_str || !domain_p || !dc_p) {
2132 p = strchr_m(domain_str, '\\');
2135 domain = talloc_strndup(mem_ctx, domain_str,
2136 PTR_DIFF(p, domain_str));
2137 dc = talloc_strdup(mem_ctx, p+1);
2142 domain = talloc_strdup(mem_ctx, domain_str);
2158 /****************************************************************
2159 ****************************************************************/
2161 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2162 struct libnet_JoinCtx *r)
2164 if (!r->in.domain_name) {
2165 libnet_join_set_error_string(mem_ctx, r,
2166 "No domain name defined");
2167 return WERR_INVALID_PARAMETER;
2170 if (strlen(r->in.machine_name) > 15) {
2171 libnet_join_set_error_string(mem_ctx, r,
2172 "Our netbios name can be at most 15 chars long, "
2173 "\"%s\" is %u chars long\n",
2175 (unsigned int)strlen(r->in.machine_name));
2176 return WERR_INVALID_PARAMETER;
2179 r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
2180 r->in.machine_name);
2181 if (r->out.account_name == NULL) {
2182 libnet_join_set_error_string(mem_ctx, r,
2183 "Unable to construct r->out.account_name");
2184 return WERR_NOT_ENOUGH_MEMORY;
2187 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2190 libnet_join_set_error_string(mem_ctx, r,
2191 "Failed to parse domain name");
2192 return WERR_INVALID_PARAMETER;
2195 if (!r->in.admin_domain) {
2196 char *admin_domain = NULL;
2197 char *admin_account = NULL;
2200 ok = split_domain_user(mem_ctx,
2201 r->in.admin_account,
2205 return WERR_NOT_ENOUGH_MEMORY;
2208 if (admin_domain != NULL) {
2209 r->in.admin_domain = admin_domain;
2211 r->in.admin_domain = r->in.domain_name;
2213 r->in.admin_account = admin_account;
2216 if (!secrets_init()) {
2217 libnet_join_set_error_string(mem_ctx, r,
2218 "Unable to open secrets database");
2219 return WERR_CAN_NOT_COMPLETE;
2225 /****************************************************************
2226 ****************************************************************/
2228 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2232 /* Try adding dom admins to builtin\admins. Only log failures. */
2233 status = create_builtin_administrators(domain_sid);
2234 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2235 DEBUG(10,("Unable to auto-add domain administrators to "
2236 "BUILTIN\\Administrators during join because "
2237 "winbindd must be running.\n"));
2238 } else if (!NT_STATUS_IS_OK(status)) {
2239 DEBUG(5, ("Failed to auto-add domain administrators to "
2240 "BUILTIN\\Administrators during join: %s\n",
2241 nt_errstr(status)));
2244 /* Try adding dom users to builtin\users. Only log failures. */
2245 status = create_builtin_users(domain_sid);
2246 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2247 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2248 "during join because winbindd must be running.\n"));
2249 } else if (!NT_STATUS_IS_OK(status)) {
2250 DEBUG(5, ("Failed to auto-add domain administrators to "
2251 "BUILTIN\\Administrators during join: %s\n",
2252 nt_errstr(status)));
2255 /* Try adding dom guests to builtin\guests. Only log failures. */
2256 status = create_builtin_guests(domain_sid);
2257 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2258 DEBUG(10,("Unable to auto-add domain guests to "
2259 "BUILTIN\\Guests during join because "
2260 "winbindd must be running.\n"));
2261 } else if (!NT_STATUS_IS_OK(status)) {
2262 DEBUG(5, ("Failed to auto-add domain guests to "
2263 "BUILTIN\\Guests during join: %s\n",
2264 nt_errstr(status)));
2268 /****************************************************************
2269 ****************************************************************/
2271 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2272 struct libnet_JoinCtx *r)
2276 if (!W_ERROR_IS_OK(r->out.result)) {
2277 return r->out.result;
2280 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2281 werr = do_JoinConfig(r);
2282 if (!W_ERROR_IS_OK(werr)) {
2290 if (r->out.domain_is_ad &&
2291 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2292 ADS_STATUS ads_status;
2294 ads_status = libnet_join_post_processing_ads_modify(mem_ctx, r);
2295 if (!ADS_ERR_OK(ads_status)) {
2296 return WERR_GEN_FAILURE;
2299 #endif /* HAVE_ADS */
2301 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2302 if (r->out.dns_domain_name) {
2303 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2306 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2307 return WERR_NERR_SETUPNOTJOINED;
2310 werr = do_JoinConfig(r);
2311 if (!W_ERROR_IS_OK(werr)) {
2316 if (r->out.domain_is_ad &&
2317 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2318 ADS_STATUS ads_status;
2320 ads_status = libnet_join_post_processing_ads_sync(mem_ctx, r);
2321 if (!ADS_ERR_OK(ads_status)) {
2322 return WERR_GEN_FAILURE;
2325 #endif /* HAVE_ADS */
2327 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2332 /****************************************************************
2333 ****************************************************************/
2335 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2338 ads_destroy(&r->in.ads);
2344 /****************************************************************
2345 ****************************************************************/
2347 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2350 ads_destroy(&r->in.ads);
2356 /****************************************************************
2357 ****************************************************************/
2359 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2360 struct libnet_JoinCtx **r)
2362 struct libnet_JoinCtx *ctx;
2364 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2366 return WERR_NOT_ENOUGH_MEMORY;
2369 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2371 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2372 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2374 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2376 ctx->in.desired_encryption_types = ENC_CRC32 |
2379 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
2380 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2382 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
2383 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2391 /****************************************************************
2392 ****************************************************************/
2394 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2395 struct libnet_UnjoinCtx **r)
2397 struct libnet_UnjoinCtx *ctx;
2399 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2401 return WERR_NOT_ENOUGH_MEMORY;
2404 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2406 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2407 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2414 /****************************************************************
2415 ****************************************************************/
2417 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2418 struct libnet_JoinCtx *r)
2420 bool valid_security = false;
2421 bool valid_workgroup = false;
2422 bool valid_realm = false;
2423 bool ignored_realm = false;
2425 /* check if configuration is already set correctly */
2427 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2429 switch (r->out.domain_is_ad) {
2431 valid_security = (lp_security() == SEC_DOMAIN)
2432 || (lp_server_role() == ROLE_DOMAIN_PDC)
2433 || (lp_server_role() == ROLE_DOMAIN_BDC);
2434 if (valid_workgroup && valid_security) {
2435 /* nothing to be done */
2440 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2441 switch (lp_security()) {
2443 if (!valid_realm && lp_winbind_rpc_only()) {
2445 ignored_realm = true;
2450 valid_security = true;
2453 if (valid_workgroup && valid_realm && valid_security) {
2454 if (ignored_realm && !r->in.modify_config)
2456 libnet_join_set_error_string(mem_ctx, r,
2457 "Warning: ignoring realm when "
2458 "joining AD domain with "
2459 "'security=domain' and "
2460 "'winbind rpc only = yes'. "
2461 "(realm set to '%s', "
2462 "should be '%s').", lp_realm(),
2463 r->out.dns_domain_name);
2465 /* nothing to be done */
2471 /* check if we are supposed to manipulate configuration */
2473 if (!r->in.modify_config) {
2475 char *wrong_conf = talloc_strdup(mem_ctx, "");
2477 if (!valid_workgroup) {
2478 wrong_conf = talloc_asprintf_append(wrong_conf,
2479 "\"workgroup\" set to '%s', should be '%s'",
2480 lp_workgroup(), r->out.netbios_domain_name);
2481 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2485 wrong_conf = talloc_asprintf_append(wrong_conf,
2486 "\"realm\" set to '%s', should be '%s'",
2487 lp_realm(), r->out.dns_domain_name);
2488 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2491 if (!valid_security) {
2492 const char *sec = NULL;
2493 switch (lp_security()) {
2494 case SEC_USER: sec = "user"; break;
2495 case SEC_DOMAIN: sec = "domain"; break;
2496 case SEC_ADS: sec = "ads"; break;
2498 wrong_conf = talloc_asprintf_append(wrong_conf,
2499 "\"security\" set to '%s', should be %s",
2500 sec, r->out.domain_is_ad ?
2501 "either 'domain' or 'ads'" : "'domain'");
2502 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2505 libnet_join_set_error_string(mem_ctx, r,
2506 "Invalid configuration (%s) and configuration modification "
2507 "was not requested", wrong_conf);
2508 return WERR_CAN_NOT_COMPLETE;
2511 /* check if we are able to manipulate configuration */
2513 if (!lp_config_backend_is_registry()) {
2514 libnet_join_set_error_string(mem_ctx, r,
2515 "Configuration manipulation requested but not "
2516 "supported by backend");
2517 return WERR_NOT_SUPPORTED;
2523 /****************************************************************
2524 ****************************************************************/
2526 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2527 struct libnet_JoinCtx *r)
2531 struct cli_state *cli = NULL;
2533 ADS_STATUS ads_status;
2534 #endif /* HAVE_ADS */
2535 const char *pre_connect_realm = NULL;
2536 const char *numeric_dcip = NULL;
2537 const char *sitename = NULL;
2539 /* Before contacting a DC, we can securely know
2540 * the realm only if the user specifies it.
2542 if (r->in.use_kerberos &&
2543 r->in.domain_name_type == JoinDomNameTypeDNS) {
2544 pre_connect_realm = r->in.domain_name;
2547 if (!r->in.dc_name) {
2548 struct netr_DsRGetDCNameInfo *info;
2550 uint32_t name_type_flags = 0;
2551 if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2552 name_type_flags = DS_IS_DNS_NAME;
2553 } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2554 name_type_flags = DS_IS_FLAT_NAME;
2556 status = dsgetdcname(mem_ctx,
2561 DS_FORCE_REDISCOVERY |
2562 DS_DIRECTORY_SERVICE_REQUIRED |
2563 DS_WRITABLE_REQUIRED |
2564 DS_RETURN_DNS_NAME |
2567 if (!NT_STATUS_IS_OK(status)) {
2568 libnet_join_set_error_string(mem_ctx, r,
2569 "failed to find DC for domain %s - %s",
2571 get_friendly_nt_error_msg(status));
2572 return WERR_NERR_DCNOTFOUND;
2575 dc = strip_hostname(info->dc_unc);
2576 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2577 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2579 if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2580 info->dc_address[1] != '\\') {
2581 DBG_ERR("ill-formed DC address '%s'\n",
2583 return WERR_NERR_DCNOTFOUND;
2586 numeric_dcip = info->dc_address + 2;
2587 sitename = info->dc_site_name;
2588 /* info goes out of scope but the memory stays
2589 allocated on the talloc context */
2592 if (pre_connect_realm != NULL) {
2593 struct sockaddr_storage ss = {0};
2595 if (numeric_dcip != NULL) {
2596 if (!interpret_string_addr(&ss, numeric_dcip,
2599 "cannot parse IP address '%s' of DC '%s'\n",
2600 numeric_dcip, r->in.dc_name);
2601 return WERR_NERR_DCNOTFOUND;
2604 if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2606 "cannot resolve IP address of DC '%s'\n",
2608 return WERR_NERR_DCNOTFOUND;
2612 /* The domain parameter is only used as modifier
2613 * to krb5.conf file name. _JOIN_ is is not a valid
2614 * NetBIOS name so it cannot clash with another domain
2617 create_local_private_krb5_conf_for_domain(pre_connect_realm,
2623 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2624 if (!NT_STATUS_IS_OK(status)) {
2625 libnet_join_set_error_string(mem_ctx, r,
2626 "failed to lookup DC info for domain '%s' over rpc: %s",
2627 r->in.domain_name, get_friendly_nt_error_msg(status));
2628 return ntstatus_to_werror(status);
2631 werr = libnet_join_check_config(mem_ctx, r);
2632 if (!W_ERROR_IS_OK(werr)) {
2638 if (r->out.domain_is_ad) {
2639 create_local_private_krb5_conf_for_domain(
2640 r->out.dns_domain_name, r->out.netbios_domain_name,
2641 sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2644 if (r->out.domain_is_ad &&
2645 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2647 const char *initial_account_ou = r->in.account_ou;
2650 * we want to create the msDS-SupportedEncryptionTypes attribute
2651 * as early as possible so always try an LDAP create as the user
2652 * first. We copy r->in.account_ou because it may be changed
2653 * during the machine pre-creation.
2656 ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2657 if (!ADS_ERR_OK(ads_status)) {
2658 return WERR_NERR_DEFAULTJOINREQUIRED;
2661 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2662 if (ADS_ERR_OK(ads_status)) {
2665 * LDAP object create succeeded, now go to the rpc
2666 * password set routines
2669 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2673 if (initial_account_ou != NULL) {
2674 libnet_join_set_error_string(mem_ctx, r,
2675 "failed to precreate account in ou %s: %s",
2677 ads_errstr(ads_status));
2678 return WERR_NERR_DEFAULTJOINREQUIRED;
2681 DBG_INFO("Failed to pre-create account in OU %s: %s\n",
2682 r->in.account_ou, ads_errstr(ads_status));
2686 #endif /* HAVE_ADS */
2688 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2689 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2690 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2692 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2694 if (!NT_STATUS_IS_OK(status)) {
2695 libnet_join_set_error_string(mem_ctx, r,
2696 "failed to join domain '%s' over rpc: %s",
2697 r->in.domain_name, get_friendly_nt_error_msg(status));
2698 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2699 return WERR_NERR_SETUPALREADYJOINED;
2701 werr = ntstatus_to_werror(status);
2715 /****************************************************************
2716 ****************************************************************/
2718 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2719 struct libnet_JoinCtx *r)
2722 struct libnet_UnjoinCtx *u = NULL;
2724 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2725 if (!W_ERROR_IS_OK(werr)) {
2729 u->in.debug = r->in.debug;
2730 u->in.dc_name = r->in.dc_name;
2731 u->in.domain_name = r->in.domain_name;
2732 u->in.admin_account = r->in.admin_account;
2733 u->in.admin_password = r->in.admin_password;
2734 u->in.modify_config = r->in.modify_config;
2735 u->in.use_kerberos = r->in.use_kerberos;
2736 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2737 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2739 werr = libnet_Unjoin(mem_ctx, u);
2745 /****************************************************************
2746 ****************************************************************/
2748 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2749 struct libnet_JoinCtx *r)
2754 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2757 ZERO_STRUCT(r->out);
2759 werr = libnet_join_pre_processing(mem_ctx, r);
2760 if (!W_ERROR_IS_OK(werr)) {
2764 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2765 werr = libnet_DomainJoin(mem_ctx, r);
2766 if (!W_ERROR_IS_OK(werr)) {
2771 werr = libnet_join_post_processing(mem_ctx, r);
2772 if (!W_ERROR_IS_OK(werr)) {
2776 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2777 werr = libnet_join_post_verify(mem_ctx, r);
2778 if (!W_ERROR_IS_OK(werr)) {
2779 libnet_join_rollback(mem_ctx, r);
2784 r->out.result = werr;
2787 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2792 /****************************************************************
2793 ****************************************************************/
2795 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2796 struct libnet_UnjoinCtx *r)
2800 if (!r->in.domain_sid) {
2802 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2803 libnet_unjoin_set_error_string(mem_ctx, r,
2804 "Unable to fetch domain sid: are we joined?");
2805 return WERR_NERR_SETUPNOTJOINED;
2807 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2808 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2811 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2812 !r->in.delete_machine_account) {
2813 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2817 if (!r->in.dc_name) {
2818 struct netr_DsRGetDCNameInfo *info;
2820 status = dsgetdcname(mem_ctx,
2825 DS_DIRECTORY_SERVICE_REQUIRED |
2826 DS_WRITABLE_REQUIRED |
2829 if (!NT_STATUS_IS_OK(status)) {
2830 libnet_unjoin_set_error_string(mem_ctx, r,
2831 "failed to find DC for domain %s - %s",
2833 get_friendly_nt_error_msg(status));
2834 return WERR_NERR_DCNOTFOUND;
2837 dc = strip_hostname(info->dc_unc);
2838 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2839 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2843 /* for net ads leave, try to delete the account. If it works,
2844 no sense in disabling. If it fails, we can still try to
2847 if (r->in.delete_machine_account) {
2848 ADS_STATUS ads_status;
2849 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2850 if (ADS_ERR_OK(ads_status)) {
2852 r->out.dns_domain_name =
2853 talloc_strdup(mem_ctx,
2854 r->in.ads->server.realm);
2856 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2858 if (!ADS_ERR_OK(ads_status)) {
2859 libnet_unjoin_set_error_string(mem_ctx, r,
2860 "failed to remove machine account from AD: %s",
2861 ads_errstr(ads_status));
2863 r->out.deleted_machine_account = true;
2864 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2865 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2869 #endif /* HAVE_ADS */
2871 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2873 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2874 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2875 if (!NT_STATUS_IS_OK(status)) {
2876 libnet_unjoin_set_error_string(mem_ctx, r,
2877 "failed to disable machine account via rpc: %s",
2878 get_friendly_nt_error_msg(status));
2879 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2880 return WERR_NERR_SETUPNOTJOINED;
2882 return ntstatus_to_werror(status);
2885 r->out.dns_domain_name = talloc_strdup(mem_ctx,
2887 r->out.disabled_machine_account = true;
2890 /* If disable succeeded or was not requested at all, we
2891 should be getting rid of our end of things */
2893 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2898 /****************************************************************
2899 ****************************************************************/
2901 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2902 struct libnet_UnjoinCtx *r)
2904 if (!r->in.domain_name) {
2905 libnet_unjoin_set_error_string(mem_ctx, r,
2906 "No domain name defined");
2907 return WERR_INVALID_PARAMETER;
2910 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2913 libnet_unjoin_set_error_string(mem_ctx, r,
2914 "Failed to parse domain name");
2915 return WERR_INVALID_PARAMETER;
2919 return WERR_NERR_SETUPDOMAINCONTROLLER;
2922 if (!r->in.admin_domain) {
2923 char *admin_domain = NULL;
2924 char *admin_account = NULL;
2927 ok = split_domain_user(mem_ctx,
2928 r->in.admin_account,
2932 return WERR_NOT_ENOUGH_MEMORY;
2935 if (admin_domain != NULL) {
2936 r->in.admin_domain = admin_domain;
2938 r->in.admin_domain = r->in.domain_name;
2940 r->in.admin_account = admin_account;
2943 if (!secrets_init()) {
2944 libnet_unjoin_set_error_string(mem_ctx, r,
2945 "Unable to open secrets database");
2946 return WERR_CAN_NOT_COMPLETE;
2952 /****************************************************************
2953 ****************************************************************/
2955 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2956 struct libnet_UnjoinCtx *r)
2958 saf_delete(r->out.netbios_domain_name);
2959 saf_delete(r->out.dns_domain_name);
2961 return libnet_unjoin_config(r);
2964 /****************************************************************
2965 ****************************************************************/
2967 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2968 struct libnet_UnjoinCtx *r)
2973 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2976 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2977 if (!W_ERROR_IS_OK(werr)) {
2981 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2982 werr = libnet_DomainUnjoin(mem_ctx, r);
2983 if (!W_ERROR_IS_OK(werr)) {
2984 libnet_unjoin_config(r);
2989 werr = libnet_unjoin_post_processing(mem_ctx, r);
2990 if (!W_ERROR_IS_OK(werr)) {
2995 r->out.result = werr;
2998 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);