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);
148 my_ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
151 SAFE_FREE(my_ads->auth.user_name);
152 my_ads->auth.user_name = SMB_STRDUP(user_name);
153 if ((cp = strchr_m(my_ads->auth.user_name, '@'))!=0) {
155 SAFE_FREE(my_ads->auth.realm);
156 my_ads->auth.realm = smb_xstrdup(cp);
157 if (!strupper_m(my_ads->auth.realm)) {
158 ads_destroy(&my_ads);
159 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
165 SAFE_FREE(my_ads->auth.password);
166 my_ads->auth.password = SMB_STRDUP(password);
169 if (ccname != NULL) {
170 SAFE_FREE(my_ads->auth.ccache_name);
171 my_ads->auth.ccache_name = SMB_STRDUP(ccname);
172 setenv(KRB5_ENV_CCNAME, my_ads->auth.ccache_name, 1);
175 status = ads_connect_user_creds(my_ads);
176 if (!ADS_ERR_OK(status)) {
177 ads_destroy(&my_ads);
185 /****************************************************************
186 ****************************************************************/
188 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
189 struct libnet_JoinCtx *r,
190 bool use_machine_creds)
193 const char *username;
194 const char *password;
195 const char *ccname = NULL;
197 if (use_machine_creds) {
198 if (r->in.machine_name == NULL ||
199 r->in.machine_password == NULL) {
200 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
202 username = talloc_asprintf(mem_ctx, "%s$",
204 if (username == NULL) {
205 return ADS_ERROR(LDAP_NO_MEMORY);
207 password = r->in.machine_password;
208 ccname = "MEMORY:libnet_join_machine_creds";
212 username = r->in.admin_account;
214 p = strchr(r->in.admin_account, '@');
216 username = talloc_asprintf(mem_ctx, "%s@%s",
220 if (username == NULL) {
221 return ADS_ERROR(LDAP_NO_MEMORY);
223 password = r->in.admin_password;
226 * when r->in.use_kerberos is set to allow "net ads join -k" we
227 * may not override the provided credential cache - gd
230 if (!r->in.use_kerberos) {
231 ccname = "MEMORY:libnet_join_user_creds";
235 status = libnet_connect_ads(r->out.dns_domain_name,
236 r->out.netbios_domain_name,
242 if (!ADS_ERR_OK(status)) {
243 libnet_join_set_error_string(mem_ctx, r,
244 "failed to connect to AD: %s",
249 if (!r->out.netbios_domain_name) {
250 r->out.netbios_domain_name = talloc_strdup(mem_ctx,
251 r->in.ads->server.workgroup);
252 ADS_ERROR_HAVE_NO_MEMORY(r->out.netbios_domain_name);
255 if (!r->out.dns_domain_name) {
256 r->out.dns_domain_name = talloc_strdup(mem_ctx,
257 r->in.ads->config.realm);
258 ADS_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
261 r->out.domain_is_ad = true;
266 /****************************************************************
267 ****************************************************************/
269 static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
270 struct libnet_JoinCtx *r)
272 return libnet_join_connect_ads(mem_ctx, r, false);
275 /****************************************************************
276 ****************************************************************/
278 static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
279 struct libnet_JoinCtx *r)
281 return libnet_join_connect_ads(mem_ctx, r, true);
284 /****************************************************************
285 ****************************************************************/
287 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
288 struct libnet_UnjoinCtx *r)
292 status = libnet_connect_ads(r->in.domain_name,
296 r->in.admin_password,
299 if (!ADS_ERR_OK(status)) {
300 libnet_unjoin_set_error_string(mem_ctx, r,
301 "failed to connect to AD: %s",
308 /****************************************************************
309 join a domain using ADS (LDAP mods)
310 ****************************************************************/
312 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
313 struct libnet_JoinCtx *r)
316 LDAPMessage *res = NULL;
317 const char *attrs[] = { "dn", NULL };
320 status = ads_check_ou_dn(mem_ctx, r->in.ads, &r->in.account_ou);
321 if (!ADS_ERR_OK(status)) {
325 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
326 if (!ADS_ERR_OK(status)) {
330 if (ads_count_replies(r->in.ads, res) != 1) {
331 ads_msgfree(r->in.ads, res);
332 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
335 ads_msgfree(r->in.ads, res);
337 /* Attempt to create the machine account and bail if this fails.
338 Assume that the admin wants exactly what they requested */
340 status = ads_create_machine_acct(r->in.ads,
343 r->in.desired_encryption_types);
345 if (ADS_ERR_OK(status)) {
346 DEBUG(1,("machine account creation created\n"));
348 } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
349 (status.err.rc == LDAP_ALREADY_EXISTS)) {
350 status = ADS_SUCCESS;
353 if (!ADS_ERR_OK(status)) {
354 DEBUG(1,("machine account creation failed\n"));
358 status = ads_move_machine_acct(r->in.ads,
362 if (!ADS_ERR_OK(status)) {
363 DEBUG(1,("failure to locate/move pre-existing "
364 "machine account\n"));
368 DEBUG(1,("The machine account %s the specified OU.\n",
369 moved ? "was moved into" : "already exists in"));
374 /****************************************************************
375 ****************************************************************/
377 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
378 struct libnet_UnjoinCtx *r)
383 status = libnet_unjoin_connect_ads(mem_ctx, r);
384 if (!ADS_ERR_OK(status)) {
385 libnet_unjoin_set_error_string(mem_ctx, r,
386 "failed to connect to AD: %s",
392 status = ads_leave_realm(r->in.ads, r->in.machine_name);
393 if (!ADS_ERR_OK(status)) {
394 libnet_unjoin_set_error_string(mem_ctx, r,
395 "failed to leave realm: %s",
403 /****************************************************************
404 ****************************************************************/
406 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
407 struct libnet_JoinCtx *r)
410 LDAPMessage *res = NULL;
413 if (!r->in.machine_name) {
414 return ADS_ERROR(LDAP_NO_MEMORY);
417 status = ads_find_machine_acct(r->in.ads,
420 if (!ADS_ERR_OK(status)) {
424 if (ads_count_replies(r->in.ads, res) != 1) {
425 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
429 dn = ads_get_dn(r->in.ads, mem_ctx, res);
431 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
435 r->out.dn = talloc_strdup(mem_ctx, dn);
437 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
441 if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
442 &r->out.set_encryption_types)) {
443 r->out.set_encryption_types = 0;
447 ads_msgfree(r->in.ads, res);
453 static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx,
454 struct libnet_JoinCtx *r,
460 if (r->in.machine_name == NULL) {
461 return ADS_ERROR_SYSTEM(EINVAL);
464 status = ads_get_service_principal_names(mem_ctx,
473 /****************************************************************
474 Set a machines dNSHostName and servicePrincipalName attributes
475 ****************************************************************/
477 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
478 struct libnet_JoinCtx *r)
483 const char **spn_array = NULL;
487 const char **netbios_aliases = NULL;
491 status = libnet_join_find_machine_acct(mem_ctx, r);
492 if (!ADS_ERR_OK(status)) {
496 status = libnet_join_get_machine_spns(mem_ctx,
498 discard_const_p(char **, &spn_array),
500 if (!ADS_ERR_OK(status)) {
501 DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
504 /* Windows only creates HOST/shortname & HOST/fqdn. */
506 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
508 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
510 if (!strupper_m(spn)) {
511 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
514 ok = ads_element_in_array(spn_array, num_spns, spn);
516 ok = add_string_to_array(spn_array, spn,
517 &spn_array, &num_spns);
519 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
523 if (!name_to_fqdn(my_fqdn, r->in.machine_name)
524 || (strchr(my_fqdn, '.') == NULL)) {
525 fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name,
526 r->out.dns_domain_name);
529 if (!strlower_m(my_fqdn)) {
530 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
533 if (!strequal(my_fqdn, r->in.machine_name)) {
534 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
536 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
539 ok = ads_element_in_array(spn_array, num_spns, spn);
541 ok = add_string_to_array(spn_array, spn,
542 &spn_array, &num_spns);
544 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
549 netbios_aliases = lp_netbios_aliases();
550 if (netbios_aliases != NULL) {
551 for (; *netbios_aliases != NULL; netbios_aliases++) {
553 * Add HOST/NETBIOSNAME
555 spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases);
558 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
560 if (!strupper_m(spn)) {
562 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
565 ok = ads_element_in_array(spn_array, num_spns, spn);
570 ok = add_string_to_array(spn_array, spn,
571 &spn_array, &num_spns);
574 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
579 * Add HOST/netbiosname.domainname
581 if (r->out.dns_domain_name == NULL) {
584 fstr_sprintf(my_fqdn, "%s.%s",
586 r->out.dns_domain_name);
588 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
590 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
593 ok = ads_element_in_array(spn_array, num_spns, spn);
598 ok = add_string_to_array(spn_array, spn,
599 &spn_array, &num_spns);
602 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
608 /* make sure to NULL terminate the array */
609 spn_array = talloc_realloc(mem_ctx, spn_array, const char *, num_spns + 1);
610 if (spn_array == NULL) {
611 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
613 spn_array[num_spns] = NULL;
615 mods = ads_init_mods(mem_ctx);
617 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
620 /* fields of primary importance */
622 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
623 if (!ADS_ERR_OK(status)) {
624 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
627 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
629 if (!ADS_ERR_OK(status)) {
630 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
633 return ads_gen_mod(r->in.ads, r->out.dn, mods);
636 /****************************************************************
637 ****************************************************************/
639 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
640 struct libnet_JoinCtx *r)
645 if (!r->in.create_upn) {
651 status = libnet_join_find_machine_acct(mem_ctx, r);
652 if (!ADS_ERR_OK(status)) {
657 const char *realm = r->out.dns_domain_name;
659 /* in case we are about to generate a keytab during the join
660 * make sure the default upn we create is usable with kinit -k.
663 if (USE_KERBEROS_KEYTAB) {
664 realm = talloc_strdup_upper(mem_ctx,
665 r->out.dns_domain_name);
669 return ADS_ERROR(LDAP_NO_MEMORY);
672 r->in.upn = talloc_asprintf(mem_ctx,
677 return ADS_ERROR(LDAP_NO_MEMORY);
681 /* now do the mods */
683 mods = ads_init_mods(mem_ctx);
685 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
688 /* fields of primary importance */
690 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
691 if (!ADS_ERR_OK(status)) {
692 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
695 return ads_gen_mod(r->in.ads, r->out.dn, mods);
699 /****************************************************************
700 ****************************************************************/
702 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
703 struct libnet_JoinCtx *r)
709 if (!r->in.os_name || !r->in.os_version ) {
715 status = libnet_join_find_machine_acct(mem_ctx, r);
716 if (!ADS_ERR_OK(status)) {
720 /* now do the mods */
722 mods = ads_init_mods(mem_ctx);
724 return ADS_ERROR(LDAP_NO_MEMORY);
727 if (r->in.os_servicepack) {
729 * if blank string then leave os_sp equal to NULL to force
730 * attribute delete (LDAP_MOD_DELETE)
732 if (!strequal(r->in.os_servicepack,"")) {
733 os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
736 os_sp = talloc_asprintf(mem_ctx, "Samba %s",
737 samba_version_string());
739 if (!os_sp && !strequal(r->in.os_servicepack,"")) {
740 return ADS_ERROR(LDAP_NO_MEMORY);
743 /* fields of primary importance */
745 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
747 if (!ADS_ERR_OK(status)) {
751 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
753 if (!ADS_ERR_OK(status)) {
757 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
759 if (!ADS_ERR_OK(status)) {
763 return ads_gen_mod(r->in.ads, r->out.dn, mods);
766 /****************************************************************
767 ****************************************************************/
769 static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
770 struct libnet_JoinCtx *r)
774 const char *etype_list_str;
776 etype_list_str = talloc_asprintf(mem_ctx, "%d",
777 r->in.desired_encryption_types);
778 if (!etype_list_str) {
779 return ADS_ERROR(LDAP_NO_MEMORY);
784 status = libnet_join_find_machine_acct(mem_ctx, r);
785 if (!ADS_ERR_OK(status)) {
789 if (r->in.desired_encryption_types == r->out.set_encryption_types) {
793 /* now do the mods */
795 mods = ads_init_mods(mem_ctx);
797 return ADS_ERROR(LDAP_NO_MEMORY);
800 status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
802 if (!ADS_ERR_OK(status)) {
806 status = ads_gen_mod(r->in.ads, r->out.dn, mods);
807 if (!ADS_ERR_OK(status)) {
811 r->out.set_encryption_types = r->in.desired_encryption_types;
816 /****************************************************************
817 ****************************************************************/
819 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
820 struct libnet_JoinCtx *r)
822 if (!USE_SYSTEM_KEYTAB) {
826 if (ads_keytab_create_default(r->in.ads) != 0) {
833 /****************************************************************
834 ****************************************************************/
836 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
837 struct libnet_JoinCtx *r)
839 uint32_t domain_func;
841 const char *salt = NULL;
842 char *std_salt = NULL;
844 status = ads_domain_func_level(r->in.ads, &domain_func);
845 if (!ADS_ERR_OK(status)) {
846 libnet_join_set_error_string(mem_ctx, r,
847 "failed to determine domain functional level: %s",
852 /* go ahead and setup the default salt */
854 std_salt = kerberos_standard_des_salt();
856 libnet_join_set_error_string(mem_ctx, r,
857 "failed to obtain standard DES salt");
861 salt = talloc_strdup(mem_ctx, std_salt);
868 /* if it's a Windows functional domain, we have to look for the UPN */
870 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
873 upn = ads_get_upn(r->in.ads, mem_ctx,
876 salt = talloc_strdup(mem_ctx, upn);
883 r->out.krb5_salt = salt;
887 /****************************************************************
888 ****************************************************************/
890 static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
891 struct libnet_JoinCtx *r)
894 bool need_etype_update = false;
897 status = libnet_join_connect_ads_user(mem_ctx, r);
898 if (!ADS_ERR_OK(status)) {
903 status = libnet_join_set_machine_spn(mem_ctx, r);
904 if (!ADS_ERR_OK(status)) {
905 libnet_join_set_error_string(mem_ctx, r,
906 "Failed to set machine spn: %s\n"
907 "Do you have sufficient permissions to create machine "
913 status = libnet_join_set_os_attributes(mem_ctx, r);
914 if (!ADS_ERR_OK(status)) {
915 libnet_join_set_error_string(mem_ctx, r,
916 "failed to set machine os attributes: %s",
921 status = libnet_join_set_machine_upn(mem_ctx, r);
922 if (!ADS_ERR_OK(status)) {
923 libnet_join_set_error_string(mem_ctx, r,
924 "failed to set machine upn: %s",
929 status = libnet_join_find_machine_acct(mem_ctx, r);
930 if (!ADS_ERR_OK(status)) {
934 if (r->in.desired_encryption_types != r->out.set_encryption_types) {
935 uint32_t func_level = 0;
937 status = ads_domain_func_level(r->in.ads, &func_level);
938 if (!ADS_ERR_OK(status)) {
939 libnet_join_set_error_string(mem_ctx, r,
940 "failed to query domain controller functional level: %s",
945 if (func_level >= DS_DOMAIN_FUNCTION_2008) {
946 need_etype_update = true;
950 if (need_etype_update) {
952 * We need to reconnect as machine account in order
953 * to update msDS-SupportedEncryptionTypes reliable
956 if (r->in.ads->auth.ccache_name != NULL) {
957 ads_kdestroy(r->in.ads->auth.ccache_name);
960 ads_destroy(&r->in.ads);
962 status = libnet_join_connect_ads_machine(mem_ctx, r);
963 if (!ADS_ERR_OK(status)) {
964 libnet_join_set_error_string(mem_ctx, r,
965 "Failed to connect as machine account: %s",
970 status = libnet_join_set_etypes(mem_ctx, r);
971 if (!ADS_ERR_OK(status)) {
972 libnet_join_set_error_string(mem_ctx, r,
973 "failed to set machine kerberos encryption types: %s",
979 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
980 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
986 static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
987 struct libnet_JoinCtx *r)
989 if (!libnet_join_create_keytab(mem_ctx, r)) {
990 libnet_join_set_error_string(mem_ctx, r,
991 "failed to create kerberos keytab");
992 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
997 #endif /* HAVE_ADS */
999 /****************************************************************
1000 Store the machine password and domain SID
1001 ****************************************************************/
1003 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
1004 struct libnet_JoinCtx *r)
1008 status = secrets_store_JoinCtx(r);
1009 if (!NT_STATUS_IS_OK(status)) {
1010 DBG_ERR("secrets_store_JoinCtx() failed %s\n",
1018 /****************************************************************
1019 Connect dc's IPC$ share
1020 ****************************************************************/
1022 static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
1027 struct cli_state **cli)
1032 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1035 if (use_kerberos && pass) {
1036 flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
1039 return cli_full_connection(cli, NULL,
1047 SMB_SIGNING_IPC_DEFAULT);
1050 /****************************************************************
1051 Lookup domain dc's info
1052 ****************************************************************/
1054 static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
1055 struct libnet_JoinCtx *r,
1056 struct cli_state **cli)
1058 struct rpc_pipe_client *pipe_hnd = NULL;
1059 struct policy_handle lsa_pol;
1060 NTSTATUS status, result;
1061 union lsa_PolicyInformation *info = NULL;
1062 struct dcerpc_binding_handle *b;
1063 const char *account = r->in.admin_account;
1064 const char *domain = r->in.admin_domain;
1065 const char *password = r->in.admin_password;
1066 bool use_kerberos = r->in.use_kerberos;
1068 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
1072 use_kerberos = false;
1075 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1081 if (!NT_STATUS_IS_OK(status)) {
1085 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc,
1087 if (!NT_STATUS_IS_OK(status)) {
1088 DEBUG(0,("Error connecting to LSA pipe. Error was %s\n",
1089 nt_errstr(status)));
1093 b = pipe_hnd->binding_handle;
1095 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true,
1096 SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1097 if (!NT_STATUS_IS_OK(status)) {
1101 status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx,
1103 LSA_POLICY_INFO_DNS,
1106 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
1107 r->out.domain_is_ad = true;
1108 r->out.netbios_domain_name = info->dns.name.string;
1109 r->out.dns_domain_name = info->dns.dns_domain.string;
1110 r->out.forest_name = info->dns.dns_forest.string;
1111 r->out.domain_guid = info->dns.domain_guid;
1112 r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
1113 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1116 if (!NT_STATUS_IS_OK(status)) {
1117 status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx,
1119 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1122 if (!NT_STATUS_IS_OK(status)) {
1125 if (!NT_STATUS_IS_OK(result)) {
1130 r->out.netbios_domain_name = info->account_domain.name.string;
1131 r->out.domain_sid = dom_sid_dup(mem_ctx, info->account_domain.sid);
1132 NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
1135 dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result);
1136 TALLOC_FREE(pipe_hnd);
1142 /****************************************************************
1143 Do the domain join unsecure
1144 ****************************************************************/
1146 static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
1147 struct libnet_JoinCtx *r,
1148 struct cli_state *cli)
1150 TALLOC_CTX *frame = talloc_stackframe();
1151 struct rpc_pipe_client *authenticate_pipe = NULL;
1152 struct rpc_pipe_client *passwordset_pipe = NULL;
1153 struct cli_credentials *cli_creds;
1154 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1155 struct netlogon_creds_CredentialState *creds = NULL;
1156 uint32_t netlogon_flags = 0;
1159 DATA_BLOB new_trust_blob = data_blob_null;
1162 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
1163 &authenticate_pipe);
1164 if (!NT_STATUS_IS_OK(status)) {
1169 if (!r->in.machine_password) {
1170 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1172 r->in.machine_password = trust_pw_new_value(mem_ctx,
1173 r->in.secure_channel_type,
1175 if (r->in.machine_password == NULL) {
1177 return NT_STATUS_NO_MEMORY;
1181 cli_creds = cli_credentials_init(talloc_tos());
1182 if (cli_creds == NULL) {
1184 return NT_STATUS_NO_MEMORY;
1187 cli_credentials_set_username(cli_creds, r->out.account_name,
1189 cli_credentials_set_domain(cli_creds, r->in.domain_name,
1191 cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
1192 cli_credentials_set_secure_channel_type(cli_creds,
1193 r->in.secure_channel_type);
1195 /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
1196 cli_credentials_set_password(cli_creds, r->in.admin_password,
1199 status = rpccli_create_netlogon_creds_ctx(
1200 cli_creds, authenticate_pipe->desthost, r->in.msg_ctx,
1201 frame, &netlogon_creds);
1202 if (!NT_STATUS_IS_OK(status)) {
1207 status = rpccli_setup_netlogon_creds(
1208 cli, NCACN_NP, netlogon_creds, true /* force_reauth */,
1210 if (!NT_STATUS_IS_OK(status)) {
1215 status = netlogon_creds_cli_get(netlogon_creds, frame, &creds);
1216 if (!NT_STATUS_IS_OK(status)) {
1221 netlogon_flags = creds->negotiate_flags;
1224 if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
1225 status = cli_rpc_pipe_open_schannel_with_creds(cli,
1226 &ndr_table_netlogon,
1230 if (!NT_STATUS_IS_OK(status)) {
1235 passwordset_pipe = authenticate_pipe;
1238 len = strlen(r->in.machine_password);
1239 ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
1240 r->in.machine_password, len,
1241 (void **)&new_trust_blob.data,
1242 &new_trust_blob.length);
1244 status = NT_STATUS_UNMAPPABLE_CHARACTER;
1245 if (errno == ENOMEM) {
1246 status = NT_STATUS_NO_MEMORY;
1252 status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
1253 passwordset_pipe->binding_handle,
1255 NULL); /* new_version */
1256 if (!NT_STATUS_IS_OK(status)) {
1262 return NT_STATUS_OK;
1265 /****************************************************************
1267 ****************************************************************/
1269 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
1270 struct libnet_JoinCtx *r,
1271 struct cli_state *cli)
1273 struct rpc_pipe_client *pipe_hnd = NULL;
1274 struct policy_handle sam_pol, domain_pol, user_pol;
1275 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1277 struct lsa_String lsa_acct_name;
1279 uint32_t acct_flags = ACB_WSTRUST;
1280 struct samr_Ids user_rids;
1281 struct samr_Ids name_types;
1282 union samr_UserInfo user_info;
1283 struct dcerpc_binding_handle *b = NULL;
1284 unsigned int old_timeout = 0;
1286 DATA_BLOB session_key = data_blob_null;
1287 struct samr_CryptPassword crypt_pwd;
1288 struct samr_CryptPasswordEx crypt_pwd_ex;
1290 ZERO_STRUCT(sam_pol);
1291 ZERO_STRUCT(domain_pol);
1292 ZERO_STRUCT(user_pol);
1294 switch (r->in.secure_channel_type) {
1295 case SEC_CHAN_WKSTA:
1296 acct_flags = ACB_WSTRUST;
1299 acct_flags = ACB_SVRTRUST;
1302 return NT_STATUS_INVALID_PARAMETER;
1305 if (!r->in.machine_password) {
1306 int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
1308 r->in.machine_password = trust_pw_new_value(mem_ctx,
1309 r->in.secure_channel_type,
1311 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
1314 /* Open the domain */
1316 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1318 if (!NT_STATUS_IS_OK(status)) {
1319 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1320 nt_errstr(status)));
1324 b = pipe_hnd->binding_handle;
1326 status = cli_get_session_key(mem_ctx, pipe_hnd, &session_key);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 DEBUG(0,("Error getting session_key of SAM pipe. Error was %s\n",
1329 nt_errstr(status)));
1333 status = dcerpc_samr_Connect2(b, mem_ctx,
1335 SAMR_ACCESS_ENUM_DOMAINS
1336 | SAMR_ACCESS_LOOKUP_DOMAIN,
1339 if (!NT_STATUS_IS_OK(status)) {
1342 if (!NT_STATUS_IS_OK(result)) {
1347 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1349 SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1
1350 | SAMR_DOMAIN_ACCESS_CREATE_USER
1351 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1355 if (!NT_STATUS_IS_OK(status)) {
1358 if (!NT_STATUS_IS_OK(result)) {
1363 /* Create domain user */
1365 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1366 if (!strlower_m(acct_name)) {
1367 status = NT_STATUS_INVALID_PARAMETER;
1371 init_lsa_String(&lsa_acct_name, acct_name);
1373 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
1374 uint32_t access_desired =
1375 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
1376 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
1377 SAMR_USER_ACCESS_SET_PASSWORD |
1378 SAMR_USER_ACCESS_GET_ATTRIBUTES |
1379 SAMR_USER_ACCESS_SET_ATTRIBUTES;
1380 uint32_t access_granted = 0;
1382 DEBUG(10,("Creating account with desired access mask: %d\n",
1385 status = dcerpc_samr_CreateUser2(b, mem_ctx,
1394 if (!NT_STATUS_IS_OK(status)) {
1399 if (!NT_STATUS_IS_OK(status) &&
1400 !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1402 DEBUG(10,("Creation of workstation account failed: %s\n",
1403 nt_errstr(status)));
1405 /* If NT_STATUS_ACCESS_DENIED then we have a valid
1406 username/password combo but the user does not have
1407 administrator access. */
1409 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1410 libnet_join_set_error_string(mem_ctx, r,
1411 "User specified does not have "
1412 "administrator privileges");
1418 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1419 if (!(r->in.join_flags &
1420 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
1425 /* We *must* do this.... don't ask... */
1427 if (NT_STATUS_IS_OK(status)) {
1428 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1432 status = dcerpc_samr_LookupNames(b, mem_ctx,
1439 if (!NT_STATUS_IS_OK(status)) {
1442 if (!NT_STATUS_IS_OK(result)) {
1446 if (user_rids.count != 1) {
1447 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1450 if (name_types.count != 1) {
1451 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1455 if (name_types.ids[0] != SID_NAME_USER) {
1456 DEBUG(0,("%s is not a user account (type=%d)\n",
1457 acct_name, name_types.ids[0]));
1458 status = NT_STATUS_INVALID_WORKSTATION;
1462 user_rid = user_rids.ids[0];
1464 /* Open handle on user */
1466 status = dcerpc_samr_OpenUser(b, mem_ctx,
1468 SEC_FLAG_MAXIMUM_ALLOWED,
1472 if (!NT_STATUS_IS_OK(status)) {
1475 if (!NT_STATUS_IS_OK(result)) {
1480 /* Fill in the additional account flags now */
1482 acct_flags |= ACB_PWNOEXP;
1484 /* Set account flags on machine account */
1485 ZERO_STRUCT(user_info.info16);
1486 user_info.info16.acct_flags = acct_flags;
1488 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1490 UserControlInformation,
1493 if (!NT_STATUS_IS_OK(status)) {
1494 dcerpc_samr_DeleteUser(b, mem_ctx,
1498 libnet_join_set_error_string(mem_ctx, r,
1499 "Failed to set account flags for machine account (%s)\n",
1504 if (!NT_STATUS_IS_OK(result)) {
1507 dcerpc_samr_DeleteUser(b, mem_ctx,
1511 libnet_join_set_error_string(mem_ctx, r,
1512 "Failed to set account flags for machine account (%s)\n",
1517 /* Set password on machine account - first try level 26 */
1520 * increase the timeout as password filter modules on the DC
1521 * might delay the operation for a significant amount of time
1523 old_timeout = rpccli_set_timeout(pipe_hnd, 600000);
1525 init_samr_CryptPasswordEx(r->in.machine_password,
1529 user_info.info26.password = crypt_pwd_ex;
1530 user_info.info26.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1532 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1534 UserInternal5InformationNew,
1538 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
1540 /* retry with level 24 */
1542 init_samr_CryptPassword(r->in.machine_password,
1546 user_info.info24.password = crypt_pwd;
1547 user_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
1549 status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
1551 UserInternal5Information,
1556 old_timeout = rpccli_set_timeout(pipe_hnd, old_timeout);
1558 if (!NT_STATUS_IS_OK(status)) {
1560 dcerpc_samr_DeleteUser(b, mem_ctx,
1564 libnet_join_set_error_string(mem_ctx, r,
1565 "Failed to set password for machine account (%s)\n",
1569 if (!NT_STATUS_IS_OK(result)) {
1572 dcerpc_samr_DeleteUser(b, mem_ctx,
1576 libnet_join_set_error_string(mem_ctx, r,
1577 "Failed to set password for machine account (%s)\n",
1582 status = NT_STATUS_OK;
1589 data_blob_clear_free(&session_key);
1591 if (is_valid_policy_hnd(&sam_pol)) {
1592 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1594 if (is_valid_policy_hnd(&domain_pol)) {
1595 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1597 if (is_valid_policy_hnd(&user_pol)) {
1598 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1600 TALLOC_FREE(pipe_hnd);
1605 /****************************************************************
1606 ****************************************************************/
1608 NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
1609 const char *netbios_domain_name,
1610 const char *dc_name,
1611 const bool use_kerberos)
1613 TALLOC_CTX *frame = talloc_stackframe();
1614 struct cli_state *cli = NULL;
1615 struct rpc_pipe_client *netlogon_pipe = NULL;
1616 struct cli_credentials *cli_creds = NULL;
1617 struct netlogon_creds_cli_context *netlogon_creds = NULL;
1618 struct netlogon_creds_CredentialState *creds = NULL;
1619 uint32_t netlogon_flags = 0;
1625 return NT_STATUS_INVALID_PARAMETER;
1628 if (!secrets_init()) {
1630 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1633 status = pdb_get_trust_credentials(netbios_domain_name, NULL,
1635 if (!NT_STATUS_IS_OK(status)) {
1640 /* we don't want any old password */
1641 cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
1644 cli_credentials_set_kerberos_state(cli_creds,
1645 CRED_MUST_USE_KERBEROS);
1648 status = cli_full_connection_creds(&cli, NULL,
1654 SMB_SIGNING_IPC_DEFAULT);
1656 if (!NT_STATUS_IS_OK(status)) {
1657 status = cli_full_connection(&cli, NULL,
1665 SMB_SIGNING_IPC_DEFAULT);
1668 if (!NT_STATUS_IS_OK(status)) {
1673 status = rpccli_create_netlogon_creds_ctx(cli_creds,
1678 if (!NT_STATUS_IS_OK(status)) {
1684 status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
1686 true, /* force_reauth */
1688 if (!NT_STATUS_IS_OK(status)) {
1689 DEBUG(0,("connect_to_domain_password_server: "
1690 "unable to open the domain client session to "
1691 "machine %s. Flags[0x%08X] Error was : %s.\n",
1692 dc_name, (unsigned)netlogon_flags,
1693 nt_errstr(status)));
1699 status = netlogon_creds_cli_get(netlogon_creds,
1702 if (!NT_STATUS_IS_OK(status)) {
1707 netlogon_flags = creds->negotiate_flags;
1710 if (!(netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1713 return NT_STATUS_OK;
1716 status = cli_rpc_pipe_open_schannel_with_creds(
1717 cli, &ndr_table_netlogon, NCACN_NP,
1718 netlogon_creds, &netlogon_pipe);
1720 TALLOC_FREE(netlogon_pipe);
1722 if (!NT_STATUS_IS_OK(status)) {
1723 DEBUG(0,("libnet_join_ok: failed to open schannel session "
1724 "on netlogon pipe to server %s for domain %s. "
1726 smbXcli_conn_remote_name(cli->conn),
1727 netbios_domain_name, nt_errstr(status)));
1735 return NT_STATUS_OK;
1738 /****************************************************************
1739 ****************************************************************/
1741 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
1742 struct libnet_JoinCtx *r)
1746 status = libnet_join_ok(r->in.msg_ctx,
1747 r->out.netbios_domain_name,
1749 r->in.use_kerberos);
1750 if (!NT_STATUS_IS_OK(status)) {
1751 libnet_join_set_error_string(mem_ctx, r,
1752 "failed to verify domain membership after joining: %s",
1753 get_friendly_nt_error_msg(status));
1754 return WERR_NERR_SETUPNOTJOINED;
1760 /****************************************************************
1761 ****************************************************************/
1763 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
1764 struct libnet_UnjoinCtx *r)
1767 * TODO: use values from 'struct libnet_UnjoinCtx' ?
1769 return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
1772 /****************************************************************
1773 ****************************************************************/
1775 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
1776 struct libnet_UnjoinCtx *r)
1778 struct cli_state *cli = NULL;
1779 struct rpc_pipe_client *pipe_hnd = NULL;
1780 struct policy_handle sam_pol, domain_pol, user_pol;
1781 NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
1784 struct lsa_String lsa_acct_name;
1785 struct samr_Ids user_rids;
1786 struct samr_Ids name_types;
1787 union samr_UserInfo *info = NULL;
1788 struct dcerpc_binding_handle *b = NULL;
1790 ZERO_STRUCT(sam_pol);
1791 ZERO_STRUCT(domain_pol);
1792 ZERO_STRUCT(user_pol);
1794 status = libnet_join_connect_dc_ipc(r->in.dc_name,
1795 r->in.admin_account,
1797 r->in.admin_password,
1800 if (!NT_STATUS_IS_OK(status)) {
1804 /* Open the domain */
1806 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr,
1808 if (!NT_STATUS_IS_OK(status)) {
1809 DEBUG(0,("Error connecting to SAM pipe. Error was %s\n",
1810 nt_errstr(status)));
1814 b = pipe_hnd->binding_handle;
1816 status = dcerpc_samr_Connect2(b, mem_ctx,
1818 SEC_FLAG_MAXIMUM_ALLOWED,
1821 if (!NT_STATUS_IS_OK(status)) {
1824 if (!NT_STATUS_IS_OK(result)) {
1829 status = dcerpc_samr_OpenDomain(b, mem_ctx,
1831 SEC_FLAG_MAXIMUM_ALLOWED,
1835 if (!NT_STATUS_IS_OK(status)) {
1838 if (!NT_STATUS_IS_OK(result)) {
1843 /* Create domain user */
1845 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
1846 if (!strlower_m(acct_name)) {
1847 status = NT_STATUS_INVALID_PARAMETER;
1851 init_lsa_String(&lsa_acct_name, acct_name);
1853 status = dcerpc_samr_LookupNames(b, mem_ctx,
1861 if (!NT_STATUS_IS_OK(status)) {
1864 if (!NT_STATUS_IS_OK(result)) {
1868 if (user_rids.count != 1) {
1869 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1872 if (name_types.count != 1) {
1873 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1877 if (name_types.ids[0] != SID_NAME_USER) {
1878 DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
1879 name_types.ids[0]));
1880 status = NT_STATUS_INVALID_WORKSTATION;
1884 user_rid = user_rids.ids[0];
1886 /* Open handle on user */
1888 status = dcerpc_samr_OpenUser(b, mem_ctx,
1890 SEC_FLAG_MAXIMUM_ALLOWED,
1894 if (!NT_STATUS_IS_OK(status)) {
1897 if (!NT_STATUS_IS_OK(result)) {
1904 status = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1909 if (!NT_STATUS_IS_OK(status)) {
1910 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1913 if (!NT_STATUS_IS_OK(result)) {
1915 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1919 /* now disable and setuser info */
1921 info->info16.acct_flags |= ACB_DISABLED;
1923 status = dcerpc_samr_SetUserInfo(b, mem_ctx,
1928 if (!NT_STATUS_IS_OK(status)) {
1929 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1932 if (!NT_STATUS_IS_OK(result)) {
1934 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1938 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result);
1941 if (pipe_hnd && b) {
1942 if (is_valid_policy_hnd(&domain_pol)) {
1943 dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result);
1945 if (is_valid_policy_hnd(&sam_pol)) {
1946 dcerpc_samr_Close(b, mem_ctx, &sam_pol, &result);
1948 TALLOC_FREE(pipe_hnd);
1958 /****************************************************************
1959 ****************************************************************/
1961 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1963 WERROR werr = WERR_OK;
1965 struct smbconf_ctx *ctx;
1967 err = smbconf_init_reg(r, &ctx, NULL);
1968 if (!SBC_ERROR_IS_OK(err)) {
1969 werr = WERR_SERVICE_DOES_NOT_EXIST;
1973 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1975 err = smbconf_set_global_parameter(ctx, "security", "user");
1976 if (!SBC_ERROR_IS_OK(err)) {
1977 werr = WERR_SERVICE_DOES_NOT_EXIST;
1981 err = smbconf_set_global_parameter(ctx, "workgroup",
1983 if (!SBC_ERROR_IS_OK(err)) {
1984 werr = WERR_SERVICE_DOES_NOT_EXIST;
1988 smbconf_delete_global_parameter(ctx, "realm");
1992 err = smbconf_set_global_parameter(ctx, "security", "domain");
1993 if (!SBC_ERROR_IS_OK(err)) {
1994 werr = WERR_SERVICE_DOES_NOT_EXIST;
1998 err = smbconf_set_global_parameter(ctx, "workgroup",
1999 r->out.netbios_domain_name);
2000 if (!SBC_ERROR_IS_OK(err)) {
2001 werr = WERR_SERVICE_DOES_NOT_EXIST;
2005 if (r->out.domain_is_ad) {
2006 err = smbconf_set_global_parameter(ctx, "security", "ads");
2007 if (!SBC_ERROR_IS_OK(err)) {
2008 werr = WERR_SERVICE_DOES_NOT_EXIST;
2012 err = smbconf_set_global_parameter(ctx, "realm",
2013 r->out.dns_domain_name);
2014 if (!SBC_ERROR_IS_OK(err)) {
2015 werr = WERR_SERVICE_DOES_NOT_EXIST;
2021 smbconf_shutdown(ctx);
2025 /****************************************************************
2026 ****************************************************************/
2028 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
2030 WERROR werr = WERR_OK;
2032 struct smbconf_ctx *ctx;
2034 err = smbconf_init_reg(r, &ctx, NULL);
2035 if (!SBC_ERROR_IS_OK(err)) {
2036 werr = WERR_SERVICE_DOES_NOT_EXIST;
2040 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2042 err = smbconf_set_global_parameter(ctx, "security", "user");
2043 if (!SBC_ERROR_IS_OK(err)) {
2044 werr = WERR_SERVICE_DOES_NOT_EXIST;
2048 err = smbconf_delete_global_parameter(ctx, "workgroup");
2049 if (!SBC_ERROR_IS_OK(err)) {
2050 werr = WERR_SERVICE_DOES_NOT_EXIST;
2054 smbconf_delete_global_parameter(ctx, "realm");
2058 smbconf_shutdown(ctx);
2062 /****************************************************************
2063 ****************************************************************/
2065 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
2069 if (!W_ERROR_IS_OK(r->out.result)) {
2070 return r->out.result;
2073 if (!r->in.modify_config) {
2077 werr = do_join_modify_vals_config(r);
2078 if (!W_ERROR_IS_OK(werr)) {
2082 lp_load_global(get_dyn_CONFIGFILE());
2084 r->out.modified_config = true;
2085 r->out.result = werr;
2090 /****************************************************************
2091 ****************************************************************/
2093 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
2097 if (!W_ERROR_IS_OK(r->out.result)) {
2098 return r->out.result;
2101 if (!r->in.modify_config) {
2105 werr = do_unjoin_modify_vals_config(r);
2106 if (!W_ERROR_IS_OK(werr)) {
2110 lp_load_global(get_dyn_CONFIGFILE());
2112 r->out.modified_config = true;
2113 r->out.result = werr;
2118 /****************************************************************
2119 ****************************************************************/
2121 static bool libnet_parse_domain_dc(TALLOC_CTX *mem_ctx,
2122 const char *domain_str,
2123 const char **domain_p,
2126 char *domain = NULL;
2128 const char *p = NULL;
2130 if (!domain_str || !domain_p || !dc_p) {
2134 p = strchr_m(domain_str, '\\');
2137 domain = talloc_strndup(mem_ctx, domain_str,
2138 PTR_DIFF(p, domain_str));
2139 dc = talloc_strdup(mem_ctx, p+1);
2144 domain = talloc_strdup(mem_ctx, domain_str);
2160 /****************************************************************
2161 ****************************************************************/
2163 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
2164 struct libnet_JoinCtx *r)
2166 if (!r->in.domain_name) {
2167 libnet_join_set_error_string(mem_ctx, r,
2168 "No domain name defined");
2169 return WERR_INVALID_PARAMETER;
2172 if (strlen(r->in.machine_name) > 15) {
2173 libnet_join_set_error_string(mem_ctx, r,
2174 "Our netbios name can be at most 15 chars long, "
2175 "\"%s\" is %u chars long\n",
2177 (unsigned int)strlen(r->in.machine_name));
2178 return WERR_INVALID_PARAMETER;
2181 r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
2182 r->in.machine_name);
2183 if (r->out.account_name == NULL) {
2184 libnet_join_set_error_string(mem_ctx, r,
2185 "Unable to construct r->out.account_name");
2186 return WERR_NOT_ENOUGH_MEMORY;
2189 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2192 libnet_join_set_error_string(mem_ctx, r,
2193 "Failed to parse domain name");
2194 return WERR_INVALID_PARAMETER;
2197 if (!r->in.admin_domain) {
2198 char *admin_domain = NULL;
2199 char *admin_account = NULL;
2202 ok = split_domain_user(mem_ctx,
2203 r->in.admin_account,
2207 return WERR_NOT_ENOUGH_MEMORY;
2210 if (admin_domain != NULL) {
2211 r->in.admin_domain = admin_domain;
2213 r->in.admin_domain = r->in.domain_name;
2215 r->in.admin_account = admin_account;
2218 if (!secrets_init()) {
2219 libnet_join_set_error_string(mem_ctx, r,
2220 "Unable to open secrets database");
2221 return WERR_CAN_NOT_COMPLETE;
2227 /****************************************************************
2228 ****************************************************************/
2230 static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
2234 /* Try adding dom admins to builtin\admins. Only log failures. */
2235 status = create_builtin_administrators(domain_sid);
2236 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2237 DEBUG(10,("Unable to auto-add domain administrators to "
2238 "BUILTIN\\Administrators during join because "
2239 "winbindd must be running.\n"));
2240 } else if (!NT_STATUS_IS_OK(status)) {
2241 DEBUG(5, ("Failed to auto-add domain administrators to "
2242 "BUILTIN\\Administrators during join: %s\n",
2243 nt_errstr(status)));
2246 /* Try adding dom users to builtin\users. Only log failures. */
2247 status = create_builtin_users(domain_sid);
2248 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2249 DEBUG(10,("Unable to auto-add domain users to BUILTIN\\users "
2250 "during join because winbindd must be running.\n"));
2251 } else if (!NT_STATUS_IS_OK(status)) {
2252 DEBUG(5, ("Failed to auto-add domain administrators to "
2253 "BUILTIN\\Administrators during join: %s\n",
2254 nt_errstr(status)));
2257 /* Try adding dom guests to builtin\guests. Only log failures. */
2258 status = create_builtin_guests(domain_sid);
2259 if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
2260 DEBUG(10,("Unable to auto-add domain guests to "
2261 "BUILTIN\\Guests during join because "
2262 "winbindd must be running.\n"));
2263 } else if (!NT_STATUS_IS_OK(status)) {
2264 DEBUG(5, ("Failed to auto-add domain guests to "
2265 "BUILTIN\\Guests during join: %s\n",
2266 nt_errstr(status)));
2270 /****************************************************************
2271 ****************************************************************/
2273 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
2274 struct libnet_JoinCtx *r)
2278 if (!W_ERROR_IS_OK(r->out.result)) {
2279 return r->out.result;
2282 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
2283 werr = do_JoinConfig(r);
2284 if (!W_ERROR_IS_OK(werr)) {
2292 if (r->out.domain_is_ad &&
2293 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2294 ADS_STATUS ads_status;
2296 ads_status = libnet_join_post_processing_ads_modify(mem_ctx, r);
2297 if (!ADS_ERR_OK(ads_status)) {
2298 return WERR_GEN_FAILURE;
2301 #endif /* HAVE_ADS */
2303 saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
2304 if (r->out.dns_domain_name) {
2305 saf_join_store(r->out.dns_domain_name, r->in.dc_name);
2308 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
2309 return WERR_NERR_SETUPNOTJOINED;
2312 werr = do_JoinConfig(r);
2313 if (!W_ERROR_IS_OK(werr)) {
2318 if (r->out.domain_is_ad &&
2319 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2320 ADS_STATUS ads_status;
2322 ads_status = libnet_join_post_processing_ads_sync(mem_ctx, r);
2323 if (!ADS_ERR_OK(ads_status)) {
2324 return WERR_GEN_FAILURE;
2327 #endif /* HAVE_ADS */
2329 libnet_join_add_dom_rids_to_builtins(r->out.domain_sid);
2334 /****************************************************************
2335 ****************************************************************/
2337 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
2340 ads_destroy(&r->in.ads);
2346 /****************************************************************
2347 ****************************************************************/
2349 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
2352 ads_destroy(&r->in.ads);
2358 /****************************************************************
2359 ****************************************************************/
2361 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
2362 struct libnet_JoinCtx **r)
2364 struct libnet_JoinCtx *ctx;
2366 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
2368 return WERR_NOT_ENOUGH_MEMORY;
2371 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
2373 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2374 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2376 ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
2378 ctx->in.desired_encryption_types = ENC_CRC32 |
2381 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
2382 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
2384 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
2385 ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
2393 /****************************************************************
2394 ****************************************************************/
2396 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
2397 struct libnet_UnjoinCtx **r)
2399 struct libnet_UnjoinCtx *ctx;
2401 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
2403 return WERR_NOT_ENOUGH_MEMORY;
2406 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
2408 ctx->in.machine_name = talloc_strdup(mem_ctx, lp_netbios_name());
2409 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
2416 /****************************************************************
2417 ****************************************************************/
2419 static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
2420 struct libnet_JoinCtx *r)
2422 bool valid_security = false;
2423 bool valid_workgroup = false;
2424 bool valid_realm = false;
2425 bool ignored_realm = false;
2427 /* check if configuration is already set correctly */
2429 valid_workgroup = strequal(lp_workgroup(), r->out.netbios_domain_name);
2431 switch (r->out.domain_is_ad) {
2433 valid_security = (lp_security() == SEC_DOMAIN)
2434 || (lp_server_role() == ROLE_DOMAIN_PDC)
2435 || (lp_server_role() == ROLE_DOMAIN_BDC);
2436 if (valid_workgroup && valid_security) {
2437 /* nothing to be done */
2442 valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
2443 switch (lp_security()) {
2445 if (!valid_realm && lp_winbind_rpc_only()) {
2447 ignored_realm = true;
2452 valid_security = true;
2455 if (valid_workgroup && valid_realm && valid_security) {
2456 if (ignored_realm && !r->in.modify_config)
2458 libnet_join_set_error_string(mem_ctx, r,
2459 "Warning: ignoring realm when "
2460 "joining AD domain with "
2461 "'security=domain' and "
2462 "'winbind rpc only = yes'. "
2463 "(realm set to '%s', "
2464 "should be '%s').", lp_realm(),
2465 r->out.dns_domain_name);
2467 /* nothing to be done */
2473 /* check if we are supposed to manipulate configuration */
2475 if (!r->in.modify_config) {
2477 char *wrong_conf = talloc_strdup(mem_ctx, "");
2479 if (!valid_workgroup) {
2480 wrong_conf = talloc_asprintf_append(wrong_conf,
2481 "\"workgroup\" set to '%s', should be '%s'",
2482 lp_workgroup(), r->out.netbios_domain_name);
2483 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2487 wrong_conf = talloc_asprintf_append(wrong_conf,
2488 "\"realm\" set to '%s', should be '%s'",
2489 lp_realm(), r->out.dns_domain_name);
2490 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2493 if (!valid_security) {
2494 const char *sec = NULL;
2495 switch (lp_security()) {
2496 case SEC_USER: sec = "user"; break;
2497 case SEC_DOMAIN: sec = "domain"; break;
2498 case SEC_ADS: sec = "ads"; break;
2500 wrong_conf = talloc_asprintf_append(wrong_conf,
2501 "\"security\" set to '%s', should be %s",
2502 sec, r->out.domain_is_ad ?
2503 "either 'domain' or 'ads'" : "'domain'");
2504 W_ERROR_HAVE_NO_MEMORY(wrong_conf);
2507 libnet_join_set_error_string(mem_ctx, r,
2508 "Invalid configuration (%s) and configuration modification "
2509 "was not requested", wrong_conf);
2510 return WERR_CAN_NOT_COMPLETE;
2513 /* check if we are able to manipulate configuration */
2515 if (!lp_config_backend_is_registry()) {
2516 libnet_join_set_error_string(mem_ctx, r,
2517 "Configuration manipulation requested but not "
2518 "supported by backend");
2519 return WERR_NOT_SUPPORTED;
2525 /****************************************************************
2526 ****************************************************************/
2528 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
2529 struct libnet_JoinCtx *r)
2533 struct cli_state *cli = NULL;
2535 ADS_STATUS ads_status;
2536 #endif /* HAVE_ADS */
2537 const char *pre_connect_realm = NULL;
2538 const char *numeric_dcip = NULL;
2539 const char *sitename = NULL;
2541 /* Before contacting a DC, we can securely know
2542 * the realm only if the user specifies it.
2544 if (r->in.use_kerberos &&
2545 r->in.domain_name_type == JoinDomNameTypeDNS) {
2546 pre_connect_realm = r->in.domain_name;
2549 if (!r->in.dc_name) {
2550 struct netr_DsRGetDCNameInfo *info;
2552 uint32_t name_type_flags = 0;
2553 if (r->in.domain_name_type == JoinDomNameTypeDNS) {
2554 name_type_flags = DS_IS_DNS_NAME;
2555 } else if (r->in.domain_name_type == JoinDomNameTypeNBT) {
2556 name_type_flags = DS_IS_FLAT_NAME;
2558 status = dsgetdcname(mem_ctx,
2563 DS_FORCE_REDISCOVERY |
2564 DS_DIRECTORY_SERVICE_REQUIRED |
2565 DS_WRITABLE_REQUIRED |
2566 DS_RETURN_DNS_NAME |
2569 if (!NT_STATUS_IS_OK(status)) {
2570 libnet_join_set_error_string(mem_ctx, r,
2571 "failed to find DC for domain %s - %s",
2573 get_friendly_nt_error_msg(status));
2574 return WERR_NERR_DCNOTFOUND;
2577 dc = strip_hostname(info->dc_unc);
2578 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2579 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2581 if (info->dc_address == NULL || info->dc_address[0] != '\\' ||
2582 info->dc_address[1] != '\\') {
2583 DBG_ERR("ill-formed DC address '%s'\n",
2585 return WERR_NERR_DCNOTFOUND;
2588 numeric_dcip = info->dc_address + 2;
2589 sitename = info->dc_site_name;
2590 /* info goes out of scope but the memory stays
2591 allocated on the talloc context */
2594 if (pre_connect_realm != NULL) {
2595 struct sockaddr_storage ss = {0};
2597 if (numeric_dcip != NULL) {
2598 if (!interpret_string_addr(&ss, numeric_dcip,
2601 "cannot parse IP address '%s' of DC '%s'\n",
2602 numeric_dcip, r->in.dc_name);
2603 return WERR_NERR_DCNOTFOUND;
2606 if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
2608 "cannot resolve IP address of DC '%s'\n",
2610 return WERR_NERR_DCNOTFOUND;
2614 /* The domain parameter is only used as modifier
2615 * to krb5.conf file name. _JOIN_ is is not a valid
2616 * NetBIOS name so it cannot clash with another domain
2619 create_local_private_krb5_conf_for_domain(pre_connect_realm,
2625 status = libnet_join_lookup_dc_rpc(mem_ctx, r, &cli);
2626 if (!NT_STATUS_IS_OK(status)) {
2627 libnet_join_set_error_string(mem_ctx, r,
2628 "failed to lookup DC info for domain '%s' over rpc: %s",
2629 r->in.domain_name, get_friendly_nt_error_msg(status));
2630 return ntstatus_to_werror(status);
2633 werr = libnet_join_check_config(mem_ctx, r);
2634 if (!W_ERROR_IS_OK(werr)) {
2640 if (r->out.domain_is_ad) {
2641 create_local_private_krb5_conf_for_domain(
2642 r->out.dns_domain_name, r->out.netbios_domain_name,
2643 sitename, smbXcli_conn_remote_sockaddr(cli->conn));
2646 if (r->out.domain_is_ad &&
2647 !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
2649 const char *initial_account_ou = r->in.account_ou;
2652 * we want to create the msDS-SupportedEncryptionTypes attribute
2653 * as early as possible so always try an LDAP create as the user
2654 * first. We copy r->in.account_ou because it may be changed
2655 * during the machine pre-creation.
2658 ads_status = libnet_join_connect_ads_user(mem_ctx, r);
2659 if (!ADS_ERR_OK(ads_status)) {
2660 libnet_join_set_error_string(mem_ctx, r,
2661 "failed to connect to AD: %s",
2662 ads_errstr(ads_status));
2663 return WERR_NERR_DEFAULTJOINREQUIRED;
2666 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
2667 if (ADS_ERR_OK(ads_status)) {
2670 * LDAP object create succeeded, now go to the rpc
2671 * password set routines
2674 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
2678 if (initial_account_ou != NULL) {
2679 libnet_join_set_error_string(mem_ctx, r,
2680 "failed to precreate account in ou %s: %s",
2682 ads_errstr(ads_status));
2683 return WERR_NERR_DEFAULTJOINREQUIRED;
2686 DBG_INFO("Failed to pre-create account in OU %s: %s\n",
2687 r->in.account_ou, ads_errstr(ads_status));
2691 #endif /* HAVE_ADS */
2693 if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
2694 (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
2695 status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
2697 status = libnet_join_joindomain_rpc(mem_ctx, r, cli);
2699 if (!NT_STATUS_IS_OK(status)) {
2700 libnet_join_set_error_string(mem_ctx, r,
2701 "failed to join domain '%s' over rpc: %s",
2702 r->in.domain_name, get_friendly_nt_error_msg(status));
2703 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
2704 return WERR_NERR_SETUPALREADYJOINED;
2706 werr = ntstatus_to_werror(status);
2720 /****************************************************************
2721 ****************************************************************/
2723 static WERROR libnet_join_rollback(TALLOC_CTX *mem_ctx,
2724 struct libnet_JoinCtx *r)
2727 struct libnet_UnjoinCtx *u = NULL;
2729 werr = libnet_init_UnjoinCtx(mem_ctx, &u);
2730 if (!W_ERROR_IS_OK(werr)) {
2734 u->in.debug = r->in.debug;
2735 u->in.dc_name = r->in.dc_name;
2736 u->in.domain_name = r->in.domain_name;
2737 u->in.admin_account = r->in.admin_account;
2738 u->in.admin_password = r->in.admin_password;
2739 u->in.modify_config = r->in.modify_config;
2740 u->in.use_kerberos = r->in.use_kerberos;
2741 u->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
2742 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
2744 werr = libnet_Unjoin(mem_ctx, u);
2750 /****************************************************************
2751 ****************************************************************/
2753 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
2754 struct libnet_JoinCtx *r)
2759 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
2762 ZERO_STRUCT(r->out);
2764 werr = libnet_join_pre_processing(mem_ctx, r);
2765 if (!W_ERROR_IS_OK(werr)) {
2769 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2770 werr = libnet_DomainJoin(mem_ctx, r);
2771 if (!W_ERROR_IS_OK(werr)) {
2776 werr = libnet_join_post_processing(mem_ctx, r);
2777 if (!W_ERROR_IS_OK(werr)) {
2781 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2782 werr = libnet_join_post_verify(mem_ctx, r);
2783 if (!W_ERROR_IS_OK(werr)) {
2784 libnet_join_rollback(mem_ctx, r);
2789 r->out.result = werr;
2792 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
2797 /****************************************************************
2798 ****************************************************************/
2800 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
2801 struct libnet_UnjoinCtx *r)
2805 if (!r->in.domain_sid) {
2807 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
2808 libnet_unjoin_set_error_string(mem_ctx, r,
2809 "Unable to fetch domain sid: are we joined?");
2810 return WERR_NERR_SETUPNOTJOINED;
2812 r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
2813 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
2816 if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) &&
2817 !r->in.delete_machine_account) {
2818 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2822 if (!r->in.dc_name) {
2823 struct netr_DsRGetDCNameInfo *info;
2825 status = dsgetdcname(mem_ctx,
2830 DS_DIRECTORY_SERVICE_REQUIRED |
2831 DS_WRITABLE_REQUIRED |
2834 if (!NT_STATUS_IS_OK(status)) {
2835 libnet_unjoin_set_error_string(mem_ctx, r,
2836 "failed to find DC for domain %s - %s",
2838 get_friendly_nt_error_msg(status));
2839 return WERR_NERR_DCNOTFOUND;
2842 dc = strip_hostname(info->dc_unc);
2843 r->in.dc_name = talloc_strdup(mem_ctx, dc);
2844 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
2848 /* for net ads leave, try to delete the account. If it works,
2849 no sense in disabling. If it fails, we can still try to
2852 if (r->in.delete_machine_account) {
2853 ADS_STATUS ads_status;
2854 ads_status = libnet_unjoin_connect_ads(mem_ctx, r);
2855 if (ADS_ERR_OK(ads_status)) {
2857 r->out.dns_domain_name =
2858 talloc_strdup(mem_ctx,
2859 r->in.ads->server.realm);
2861 libnet_unjoin_remove_machine_acct(mem_ctx, r);
2863 if (!ADS_ERR_OK(ads_status)) {
2864 libnet_unjoin_set_error_string(mem_ctx, r,
2865 "failed to remove machine account from AD: %s",
2866 ads_errstr(ads_status));
2868 r->out.deleted_machine_account = true;
2869 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
2870 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2874 #endif /* HAVE_ADS */
2876 /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means
2878 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
2879 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
2880 if (!NT_STATUS_IS_OK(status)) {
2881 libnet_unjoin_set_error_string(mem_ctx, r,
2882 "failed to disable machine account via rpc: %s",
2883 get_friendly_nt_error_msg(status));
2884 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
2885 return WERR_NERR_SETUPNOTJOINED;
2887 return ntstatus_to_werror(status);
2890 r->out.dns_domain_name = talloc_strdup(mem_ctx,
2892 r->out.disabled_machine_account = true;
2895 /* If disable succeeded or was not requested at all, we
2896 should be getting rid of our end of things */
2898 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
2903 /****************************************************************
2904 ****************************************************************/
2906 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
2907 struct libnet_UnjoinCtx *r)
2909 if (!r->in.domain_name) {
2910 libnet_unjoin_set_error_string(mem_ctx, r,
2911 "No domain name defined");
2912 return WERR_INVALID_PARAMETER;
2915 if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
2918 libnet_unjoin_set_error_string(mem_ctx, r,
2919 "Failed to parse domain name");
2920 return WERR_INVALID_PARAMETER;
2924 return WERR_NERR_SETUPDOMAINCONTROLLER;
2927 if (!r->in.admin_domain) {
2928 char *admin_domain = NULL;
2929 char *admin_account = NULL;
2932 ok = split_domain_user(mem_ctx,
2933 r->in.admin_account,
2937 return WERR_NOT_ENOUGH_MEMORY;
2940 if (admin_domain != NULL) {
2941 r->in.admin_domain = admin_domain;
2943 r->in.admin_domain = r->in.domain_name;
2945 r->in.admin_account = admin_account;
2948 if (!secrets_init()) {
2949 libnet_unjoin_set_error_string(mem_ctx, r,
2950 "Unable to open secrets database");
2951 return WERR_CAN_NOT_COMPLETE;
2957 /****************************************************************
2958 ****************************************************************/
2960 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
2961 struct libnet_UnjoinCtx *r)
2963 saf_delete(r->out.netbios_domain_name);
2964 saf_delete(r->out.dns_domain_name);
2966 return libnet_unjoin_config(r);
2969 /****************************************************************
2970 ****************************************************************/
2972 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
2973 struct libnet_UnjoinCtx *r)
2978 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
2981 werr = libnet_unjoin_pre_processing(mem_ctx, r);
2982 if (!W_ERROR_IS_OK(werr)) {
2986 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
2987 werr = libnet_DomainUnjoin(mem_ctx, r);
2988 if (!W_ERROR_IS_OK(werr)) {
2989 libnet_unjoin_config(r);
2994 werr = libnet_unjoin_post_processing(mem_ctx, r);
2995 if (!W_ERROR_IS_OK(werr)) {
3000 r->out.result = werr;
3003 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);