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/>.
22 #include "libnet/libnet.h"
24 /****************************************************************
25 ****************************************************************/
27 #define LIBNET_JOIN_DUMP_CTX(ctx, r, f) \
30 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_JoinCtx, f, r); \
31 DEBUG(1,("libnet_Join:\n%s", str)); \
35 #define LIBNET_JOIN_IN_DUMP_CTX(ctx, r) \
36 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
37 #define LIBNET_JOIN_OUT_DUMP_CTX(ctx, r) \
38 LIBNET_JOIN_DUMP_CTX(ctx, r, NDR_OUT)
40 #define LIBNET_UNJOIN_DUMP_CTX(ctx, r, f) \
43 str = NDR_PRINT_FUNCTION_STRING(ctx, libnet_UnjoinCtx, f, r); \
44 DEBUG(1,("libnet_Unjoin:\n%s", str)); \
48 #define LIBNET_UNJOIN_IN_DUMP_CTX(ctx, r) \
49 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_IN | NDR_SET_VALUES)
50 #define LIBNET_UNJOIN_OUT_DUMP_CTX(ctx, r) \
51 LIBNET_UNJOIN_DUMP_CTX(ctx, r, NDR_OUT)
53 #define W_ERROR_NOT_OK_GOTO_DONE(x) do { \
54 if (!W_ERROR_IS_OK(x)) {\
59 /****************************************************************
60 ****************************************************************/
62 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
63 struct libnet_JoinCtx *r,
64 const char *format, ...)
68 if (r->out.error_string) {
72 va_start(args, format);
73 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
77 /****************************************************************
78 ****************************************************************/
80 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
81 struct libnet_UnjoinCtx *r,
82 const char *format, ...)
86 if (r->out.error_string) {
90 va_start(args, format);
91 r->out.error_string = talloc_vasprintf(mem_ctx, format, args);
97 /****************************************************************
98 ****************************************************************/
100 static ADS_STATUS libnet_connect_ads(const char *dns_domain_name,
101 const char *netbios_domain_name,
103 const char *user_name,
104 const char *password,
108 ADS_STRUCT *my_ads = NULL;
110 my_ads = ads_init(dns_domain_name,
114 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
118 SAFE_FREE(my_ads->auth.user_name);
119 my_ads->auth.user_name = SMB_STRDUP(user_name);
123 SAFE_FREE(my_ads->auth.password);
124 my_ads->auth.password = SMB_STRDUP(password);
127 status = ads_connect(my_ads);
128 if (!ADS_ERR_OK(status)) {
129 ads_destroy(&my_ads);
137 /****************************************************************
138 ****************************************************************/
140 static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
141 struct libnet_JoinCtx *r)
145 status = libnet_connect_ads(r->in.domain_name,
149 r->in.admin_password,
151 if (!ADS_ERR_OK(status)) {
152 libnet_join_set_error_string(mem_ctx, r,
153 "failed to connect to AD: %s",
160 /****************************************************************
161 ****************************************************************/
163 static ADS_STATUS libnet_unjoin_connect_ads(TALLOC_CTX *mem_ctx,
164 struct libnet_UnjoinCtx *r)
168 status = libnet_connect_ads(r->in.domain_name,
172 r->in.admin_password,
174 if (!ADS_ERR_OK(status)) {
175 libnet_unjoin_set_error_string(mem_ctx, r,
176 "failed to connect to AD: %s",
183 /****************************************************************
184 ****************************************************************/
186 static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
187 struct libnet_JoinCtx *r)
190 LDAPMessage *res = NULL;
191 const char *attrs[] = { "dn", NULL };
193 status = ads_search_dn(r->in.ads, &res, r->in.account_ou, attrs);
194 if (!ADS_ERR_OK(status)) {
198 if (ads_count_replies(r->in.ads, res) != 1) {
199 ads_msgfree(r->in.ads, res);
200 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
203 status = ads_create_machine_acct(r->in.ads,
206 ads_msgfree(r->in.ads, res);
208 if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
209 (status.err.rc == LDAP_ALREADY_EXISTS)) {
210 status = ADS_SUCCESS;
216 /****************************************************************
217 ****************************************************************/
219 static ADS_STATUS libnet_unjoin_remove_machine_acct(TALLOC_CTX *mem_ctx,
220 struct libnet_UnjoinCtx *r)
225 status = libnet_unjoin_connect_ads(mem_ctx, r);
226 if (!ADS_ERR_OK(status)) {
231 status = ads_leave_realm(r->in.ads, r->in.machine_name);
232 if (!ADS_ERR_OK(status)) {
233 libnet_unjoin_set_error_string(mem_ctx, r,
234 "failed to leave realm: %s",
242 /****************************************************************
243 ****************************************************************/
245 static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
246 struct libnet_JoinCtx *r)
249 LDAPMessage *res = NULL;
252 if (!r->in.machine_name) {
253 return ADS_ERROR(LDAP_NO_MEMORY);
256 status = ads_find_machine_acct(r->in.ads,
259 if (!ADS_ERR_OK(status)) {
263 if (ads_count_replies(r->in.ads, res) != 1) {
264 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
268 dn = ads_get_dn(r->in.ads, res);
270 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
274 r->out.dn = talloc_strdup(mem_ctx, dn);
276 status = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
281 ads_msgfree(r->in.ads, res);
282 ads_memfree(r->in.ads, dn);
287 /****************************************************************
288 ****************************************************************/
290 static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
291 struct libnet_JoinCtx *r)
296 const char *spn_array[3] = {NULL, NULL, NULL};
299 status = libnet_join_find_machine_acct(mem_ctx, r);
300 if (!ADS_ERR_OK(status)) {
304 spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
306 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
311 if (name_to_fqdn(my_fqdn, r->in.machine_name) &&
312 !strequal(my_fqdn, r->in.machine_name)) {
315 spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
317 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
322 mods = ads_init_mods(mem_ctx);
324 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
327 status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn);
328 if (!ADS_ERR_OK(status)) {
329 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
332 status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName",
334 if (!ADS_ERR_OK(status)) {
335 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
338 return ads_gen_mod(r->in.ads, r->out.dn, mods);
341 /****************************************************************
342 ****************************************************************/
344 static ADS_STATUS libnet_join_set_machine_upn(TALLOC_CTX *mem_ctx,
345 struct libnet_JoinCtx *r)
350 if (!r->in.create_upn) {
354 status = libnet_join_find_machine_acct(mem_ctx, r);
355 if (!ADS_ERR_OK(status)) {
360 r->in.upn = talloc_asprintf(mem_ctx,
363 r->out.dns_domain_name);
365 return ADS_ERROR(LDAP_NO_MEMORY);
369 mods = ads_init_mods(mem_ctx);
371 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
374 status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", r->in.upn);
375 if (!ADS_ERR_OK(status)) {
376 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
379 return ads_gen_mod(r->in.ads, r->out.dn, mods);
383 /****************************************************************
384 ****************************************************************/
386 static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
387 struct libnet_JoinCtx *r)
393 if (!r->in.os_name || !r->in.os_version ) {
397 status = libnet_join_find_machine_acct(mem_ctx, r);
398 if (!ADS_ERR_OK(status)) {
402 mods = ads_init_mods(mem_ctx);
404 return ADS_ERROR(LDAP_NO_MEMORY);
407 os_sp = talloc_asprintf(mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
409 return ADS_ERROR(LDAP_NO_MEMORY);
412 status = ads_mod_str(mem_ctx, &mods, "operatingSystem",
414 if (!ADS_ERR_OK(status)) {
418 status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion",
420 if (!ADS_ERR_OK(status)) {
424 status = ads_mod_str(mem_ctx, &mods, "operatingSystemServicePack",
426 if (!ADS_ERR_OK(status)) {
430 return ads_gen_mod(r->in.ads, r->out.dn, mods);
433 /****************************************************************
434 ****************************************************************/
436 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
437 struct libnet_JoinCtx *r)
439 if (!lp_use_kerberos_keytab()) {
443 if (!ads_keytab_create_default(r->in.ads)) {
450 /****************************************************************
451 ****************************************************************/
453 static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
454 struct libnet_JoinCtx *r)
456 uint32_t domain_func;
458 const char *salt = NULL;
459 char *std_salt = NULL;
461 status = ads_domain_func_level(r->in.ads, &domain_func);
462 if (!ADS_ERR_OK(status)) {
463 libnet_join_set_error_string(mem_ctx, r,
464 "failed to determine domain functional level: %s",
469 std_salt = kerberos_standard_des_salt();
471 libnet_join_set_error_string(mem_ctx, r,
472 "failed to obtain standard DES salt");
476 salt = talloc_strdup(mem_ctx, std_salt);
483 if (domain_func == DS_DOMAIN_FUNCTION_2000) {
486 upn = ads_get_upn(r->in.ads, mem_ctx,
489 salt = talloc_strdup(mem_ctx, upn);
496 return kerberos_secrets_store_des_salt(salt);
499 /****************************************************************
500 ****************************************************************/
502 static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
503 struct libnet_JoinCtx *r)
508 status = libnet_join_connect_ads(mem_ctx, r);
509 if (!ADS_ERR_OK(status)) {
514 status = libnet_join_set_machine_spn(mem_ctx, r);
515 if (!ADS_ERR_OK(status)) {
516 libnet_join_set_error_string(mem_ctx, r,
517 "failed to set machine spn: %s",
522 status = libnet_join_set_os_attributes(mem_ctx, r);
523 if (!ADS_ERR_OK(status)) {
524 libnet_join_set_error_string(mem_ctx, r,
525 "failed to set machine os attributes: %s",
530 status = libnet_join_set_machine_upn(mem_ctx, r);
531 if (!ADS_ERR_OK(status)) {
532 libnet_join_set_error_string(mem_ctx, r,
533 "failed to set machine upn: %s",
538 if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
539 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
542 if (!libnet_join_create_keytab(mem_ctx, r)) {
543 libnet_join_set_error_string(mem_ctx, r,
544 "failed to create kerberos keytab");
545 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
550 #endif /* WITH_ADS */
552 /****************************************************************
553 ****************************************************************/
555 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
556 struct libnet_JoinCtx *r)
558 if (!secrets_store_domain_sid(r->out.netbios_domain_name,
564 if (!secrets_store_machine_password(r->in.machine_password,
565 r->out.netbios_domain_name,
574 /****************************************************************
575 ****************************************************************/
577 static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
578 struct libnet_JoinCtx *r)
580 struct cli_state *cli = NULL;
581 struct rpc_pipe_client *pipe_hnd = NULL;
582 POLICY_HND sam_pol, domain_pol, user_pol, lsa_pol;
583 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
585 struct lsa_String lsa_acct_name;
587 uint32 acb_info = ACB_WSTRUST;
589 struct MD5Context md5ctx;
591 DATA_BLOB digested_session_key;
592 uchar md4_trust_password[16];
593 union lsa_PolicyInformation *info = NULL;
594 struct samr_Ids user_rids;
595 struct samr_Ids name_types;
596 union samr_UserInfo user_info;
598 if (!r->in.machine_password) {
599 r->in.machine_password = talloc_strdup(mem_ctx, generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH));
600 NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
603 status = cli_full_connection(&cli, NULL,
609 r->in.admin_password,
613 if (!NT_STATUS_IS_OK(status)) {
617 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
622 status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
623 SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
624 if (!NT_STATUS_IS_OK(status)) {
628 status = rpccli_lsa_QueryInfoPolicy2(pipe_hnd, mem_ctx,
632 if (NT_STATUS_IS_OK(status)) {
633 r->out.domain_is_ad = true;
634 r->out.netbios_domain_name = info->dns.name.string;
635 r->out.dns_domain_name = info->dns.dns_domain.string;
636 r->out.domain_sid = info->dns.sid;
639 if (!NT_STATUS_IS_OK(status)) {
640 status = rpccli_lsa_QueryInfoPolicy(pipe_hnd, mem_ctx,
642 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
644 if (!NT_STATUS_IS_OK(status)) {
648 r->out.netbios_domain_name = info->account_domain.name.string;
649 r->out.domain_sid = info->account_domain.sid;
652 rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
653 cli_rpc_pipe_close(pipe_hnd);
655 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
660 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
661 pipe_hnd->cli->desthost,
662 SEC_RIGHTS_MAXIMUM_ALLOWED,
664 if (!NT_STATUS_IS_OK(status)) {
668 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
670 SEC_RIGHTS_MAXIMUM_ALLOWED,
673 if (!NT_STATUS_IS_OK(status)) {
677 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
678 strlower_m(acct_name);
680 init_lsa_String(&lsa_acct_name, acct_name);
682 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE) {
683 uint32_t acct_flags =
684 SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE |
685 SEC_STD_WRITE_DAC | SEC_STD_DELETE |
686 SAMR_USER_ACCESS_SET_PASSWORD |
687 SAMR_USER_ACCESS_GET_ATTRIBUTES |
688 SAMR_USER_ACCESS_SET_ATTRIBUTES;
689 uint32_t access_granted = 0;
691 status = rpccli_samr_CreateUser2(pipe_hnd, mem_ctx,
699 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
700 if (!(r->in.join_flags &
701 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED)) {
706 if (NT_STATUS_IS_OK(status)) {
707 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
711 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
717 if (!NT_STATUS_IS_OK(status)) {
721 if (name_types.ids[0] != SID_NAME_USER) {
722 status = NT_STATUS_INVALID_WORKSTATION;
726 user_rid = user_rids.ids[0];
728 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
730 SEC_RIGHTS_MAXIMUM_ALLOWED,
733 if (!NT_STATUS_IS_OK(status)) {
737 E_md4hash(r->in.machine_password, md4_trust_password);
738 encode_pw_buffer(pwbuf, r->in.machine_password, STR_UNICODE);
740 generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer));
741 digested_session_key = data_blob_talloc(mem_ctx, 0, 16);
744 MD5Update(&md5ctx, md5buffer, sizeof(md5buffer));
745 MD5Update(&md5ctx, cli->user_session_key.data,
746 cli->user_session_key.length);
747 MD5Final(digested_session_key.data, &md5ctx);
749 SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key);
750 memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer));
752 acb_info |= ACB_PWNOEXP;
753 if (r->out.domain_is_ad) {
754 #if !defined(ENCTYPE_ARCFOUR_HMAC)
755 acb_info |= ACB_USE_DES_KEY_ONLY;
760 ZERO_STRUCT(user_info.info25);
762 user_info.info25.info.fields_present = ACCT_NT_PWD_SET |
764 SAMR_FIELD_ACCT_FLAGS;
765 user_info.info25.info.acct_flags = acb_info;
766 memcpy(&user_info.info25.password.data, pwbuf, sizeof(pwbuf));
768 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
772 if (!NT_STATUS_IS_OK(status)) {
776 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
777 cli_rpc_pipe_close(pipe_hnd);
779 status = NT_STATUS_OK;
788 /****************************************************************
789 ****************************************************************/
791 NTSTATUS libnet_join_ok(const char *netbios_domain_name,
792 const char *machine_name,
795 uint32_t neg_flags = NETLOGON_NEG_AUTH2_FLAGS |
796 NETLOGON_NEG_SCHANNEL;
797 /* FIXME: NETLOGON_NEG_SELECT_AUTH2_FLAGS */
798 struct cli_state *cli = NULL;
799 struct rpc_pipe_client *pipe_hnd = NULL;
800 struct rpc_pipe_client *netlogon_pipe = NULL;
802 char *machine_password = NULL;
803 char *machine_account = NULL;
806 return NT_STATUS_INVALID_PARAMETER;
809 if (!secrets_init()) {
810 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
813 machine_password = secrets_fetch_machine_password(netbios_domain_name,
815 if (!machine_password) {
816 return NT_STATUS_NO_TRUST_LSA_SECRET;
819 asprintf(&machine_account, "%s$", machine_name);
820 if (!machine_account) {
821 SAFE_FREE(machine_password);
822 return NT_STATUS_NO_MEMORY;
825 status = cli_full_connection(&cli, NULL,
834 free(machine_account);
835 free(machine_password);
837 if (!NT_STATUS_IS_OK(status)) {
838 status = cli_full_connection(&cli, NULL,
849 if (!NT_STATUS_IS_OK(status)) {
853 netlogon_pipe = get_schannel_session_key(cli,
855 &neg_flags, &status);
856 if (!netlogon_pipe) {
857 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
862 DEBUG(0,("libnet_join_ok: failed to get schannel session "
863 "key from server %s for domain %s. Error was %s\n",
864 cli->desthost, netbios_domain_name, nt_errstr(status)));
869 if (!lp_client_schannel()) {
874 pipe_hnd = cli_rpc_pipe_open_schannel_with_key(cli, PI_NETLOGON,
875 PIPE_AUTH_LEVEL_PRIVACY,
883 DEBUG(0,("libnet_join_ok: failed to open schannel session "
884 "on netlogon pipe to server %s for domain %s. "
886 cli->desthost, netbios_domain_name, nt_errstr(status)));
893 /****************************************************************
894 ****************************************************************/
896 static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
897 struct libnet_JoinCtx *r)
901 status = libnet_join_ok(r->out.netbios_domain_name,
904 if (!NT_STATUS_IS_OK(status)) {
905 libnet_join_set_error_string(mem_ctx, r,
906 "failed to verify domain membership after joining: %s",
907 get_friendly_nt_error_msg(status));
908 return WERR_SETUP_NOT_JOINED;
914 /****************************************************************
915 ****************************************************************/
917 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
918 struct libnet_UnjoinCtx *r)
920 if (!secrets_delete_machine_password_ex(lp_workgroup())) {
924 if (!secrets_delete_domain_sid(lp_workgroup())) {
931 /****************************************************************
932 ****************************************************************/
934 static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
935 struct libnet_UnjoinCtx *r)
937 struct cli_state *cli = NULL;
938 struct rpc_pipe_client *pipe_hnd = NULL;
939 POLICY_HND sam_pol, domain_pol, user_pol;
940 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
943 struct lsa_String lsa_acct_name;
944 struct samr_Ids user_rids;
945 struct samr_Ids name_types;
946 union samr_UserInfo *info = NULL;
948 status = cli_full_connection(&cli, NULL,
954 r->in.admin_password,
957 if (!NT_STATUS_IS_OK(status)) {
961 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
966 status = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
967 pipe_hnd->cli->desthost,
968 SEC_RIGHTS_MAXIMUM_ALLOWED,
970 if (!NT_STATUS_IS_OK(status)) {
974 status = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
976 SEC_RIGHTS_MAXIMUM_ALLOWED,
979 if (!NT_STATUS_IS_OK(status)) {
983 acct_name = talloc_asprintf(mem_ctx, "%s$", r->in.machine_name);
984 strlower_m(acct_name);
986 init_lsa_String(&lsa_acct_name, acct_name);
988 status = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
995 if (!NT_STATUS_IS_OK(status)) {
999 if (name_types.ids[0] != SID_NAME_USER) {
1000 status = NT_STATUS_INVALID_WORKSTATION;
1004 user_rid = user_rids.ids[0];
1006 status = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1008 SEC_RIGHTS_MAXIMUM_ALLOWED,
1011 if (!NT_STATUS_IS_OK(status)) {
1015 status = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1019 if (!NT_STATUS_IS_OK(status)) {
1020 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1024 info->info16.acct_flags |= ACB_DISABLED;
1026 status = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1031 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1035 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1036 rpccli_samr_Close(pipe_hnd, mem_ctx, &sam_pol);
1037 cli_rpc_pipe_close(pipe_hnd);
1047 /****************************************************************
1048 ****************************************************************/
1050 static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
1053 struct libnet_conf_ctx *ctx;
1055 werr = libnet_conf_open(r, &ctx);
1056 if (!W_ERROR_IS_OK(werr)) {
1060 if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
1062 werr = libnet_conf_set_global_parameter(ctx, "security", "user");
1063 W_ERROR_NOT_OK_GOTO_DONE(werr);
1065 werr = libnet_conf_set_global_parameter(ctx, "workgroup",
1070 werr = libnet_conf_set_global_parameter(ctx, "security", "domain");
1071 W_ERROR_NOT_OK_GOTO_DONE(werr);
1073 werr = libnet_conf_set_global_parameter(ctx, "workgroup",
1074 r->out.netbios_domain_name);
1075 W_ERROR_NOT_OK_GOTO_DONE(werr);
1077 if (r->out.domain_is_ad) {
1078 werr = libnet_conf_set_global_parameter(ctx, "security", "ads");
1079 W_ERROR_NOT_OK_GOTO_DONE(werr);
1081 werr = libnet_conf_set_global_parameter(ctx, "realm",
1082 r->out.dns_domain_name);
1083 W_ERROR_NOT_OK_GOTO_DONE(werr);
1087 libnet_conf_close(ctx);
1091 /****************************************************************
1092 ****************************************************************/
1094 static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
1096 WERROR werr = WERR_OK;
1097 struct libnet_conf_ctx *ctx;
1099 werr = libnet_conf_open(r, &ctx);
1100 if (!W_ERROR_IS_OK(werr)) {
1104 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1106 werr = libnet_conf_set_global_parameter(ctx, "security", "user");
1107 W_ERROR_NOT_OK_GOTO_DONE(werr);
1108 libnet_conf_delete_global_parameter(ctx, "realm");
1112 libnet_conf_close(ctx);
1116 /****************************************************************
1117 ****************************************************************/
1119 static WERROR do_JoinConfig(struct libnet_JoinCtx *r)
1123 if (!W_ERROR_IS_OK(r->out.result)) {
1124 return r->out.result;
1127 if (!r->in.modify_config) {
1131 werr = do_join_modify_vals_config(r);
1132 if (!W_ERROR_IS_OK(werr)) {
1136 r->out.modified_config = true;
1137 r->out.result = werr;
1142 /****************************************************************
1143 ****************************************************************/
1145 static WERROR libnet_unjoin_config(struct libnet_UnjoinCtx *r)
1149 if (!W_ERROR_IS_OK(r->out.result)) {
1150 return r->out.result;
1153 if (!r->in.modify_config) {
1157 werr = do_unjoin_modify_vals_config(r);
1158 if (!W_ERROR_IS_OK(werr)) {
1162 r->out.modified_config = true;
1163 r->out.result = werr;
1168 /****************************************************************
1169 ****************************************************************/
1171 static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
1172 struct libnet_JoinCtx *r)
1174 if (!r->in.domain_name) {
1175 libnet_join_set_error_string(mem_ctx, r,
1176 "No domain name defined");
1177 return WERR_INVALID_PARAM;
1180 if (r->in.modify_config && !lp_config_backend_is_registry()) {
1181 return WERR_NOT_SUPPORTED;
1185 return WERR_SETUP_DOMAIN_CONTROLLER;
1188 if (!secrets_init()) {
1189 libnet_join_set_error_string(mem_ctx, r,
1190 "Unable to open secrets database");
1191 return WERR_CAN_NOT_COMPLETE;
1197 /****************************************************************
1198 ****************************************************************/
1200 static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
1201 struct libnet_JoinCtx *r)
1205 if (!W_ERROR_IS_OK(r->out.result)) {
1206 return r->out.result;
1209 werr = do_JoinConfig(r);
1210 if (!W_ERROR_IS_OK(werr)) {
1214 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1215 saf_store(r->in.domain_name, r->in.dc_name);
1221 /****************************************************************
1222 ****************************************************************/
1224 static int libnet_destroy_JoinCtx(struct libnet_JoinCtx *r)
1227 ads_destroy(&r->in.ads);
1233 /****************************************************************
1234 ****************************************************************/
1236 static int libnet_destroy_UnjoinCtx(struct libnet_UnjoinCtx *r)
1239 ads_destroy(&r->in.ads);
1245 /****************************************************************
1246 ****************************************************************/
1248 WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
1249 struct libnet_JoinCtx **r)
1251 struct libnet_JoinCtx *ctx;
1253 ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
1258 talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
1260 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1261 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1268 /****************************************************************
1269 ****************************************************************/
1271 WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
1272 struct libnet_UnjoinCtx **r)
1274 struct libnet_UnjoinCtx *ctx;
1276 ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
1281 talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
1283 ctx->in.machine_name = talloc_strdup(mem_ctx, global_myname());
1284 W_ERROR_HAVE_NO_MEMORY(ctx->in.machine_name);
1291 /****************************************************************
1292 ****************************************************************/
1294 static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
1295 struct libnet_JoinCtx *r)
1299 ADS_STATUS ads_status;
1300 #endif /* WITH_ADS */
1302 if (!r->in.dc_name) {
1303 struct DS_DOMAIN_CONTROLLER_INFO *info;
1304 status = dsgetdcname(mem_ctx,
1308 DS_DIRECTORY_SERVICE_REQUIRED |
1309 DS_WRITABLE_REQUIRED |
1312 if (!NT_STATUS_IS_OK(status)) {
1313 libnet_join_set_error_string(mem_ctx, r,
1314 "failed to find DC for domain %s",
1316 get_friendly_nt_error_msg(status));
1317 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1320 r->in.dc_name = talloc_strdup(mem_ctx,
1321 info->domain_controller_name);
1322 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1326 if (r->in.account_ou) {
1328 ads_status = libnet_join_connect_ads(mem_ctx, r);
1329 if (!ADS_ERR_OK(ads_status)) {
1330 return WERR_DEFAULT_JOIN_REQUIRED;
1333 ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
1334 if (!ADS_ERR_OK(ads_status)) {
1335 libnet_join_set_error_string(mem_ctx, r,
1336 "failed to precreate account in ou %s: %s",
1338 ads_errstr(ads_status));
1339 return WERR_DEFAULT_JOIN_REQUIRED;
1342 r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
1344 #endif /* WITH_ADS */
1346 status = libnet_join_joindomain_rpc(mem_ctx, r);
1347 if (!NT_STATUS_IS_OK(status)) {
1348 libnet_join_set_error_string(mem_ctx, r,
1349 "failed to join domain over rpc: %s",
1350 get_friendly_nt_error_msg(status));
1351 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
1352 return WERR_SETUP_ALREADY_JOINED;
1354 return ntstatus_to_werror(status);
1357 if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
1358 return WERR_SETUP_NOT_JOINED;
1362 if (r->out.domain_is_ad) {
1363 ads_status = libnet_join_post_processing_ads(mem_ctx, r);
1364 if (!ADS_ERR_OK(ads_status)) {
1365 return WERR_GENERAL_FAILURE;
1368 #endif /* WITH_ADS */
1373 /****************************************************************
1374 ****************************************************************/
1376 WERROR libnet_Join(TALLOC_CTX *mem_ctx,
1377 struct libnet_JoinCtx *r)
1382 LIBNET_JOIN_IN_DUMP_CTX(mem_ctx, r);
1385 werr = libnet_join_pre_processing(mem_ctx, r);
1386 if (!W_ERROR_IS_OK(werr)) {
1390 if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1391 werr = libnet_DomainJoin(mem_ctx, r);
1392 if (!W_ERROR_IS_OK(werr)) {
1396 werr = libnet_join_post_verify(mem_ctx, r);
1397 if (!W_ERROR_IS_OK(werr)) {
1402 werr = libnet_join_post_processing(mem_ctx, r);
1403 if (!W_ERROR_IS_OK(werr)) {
1407 r->out.result = werr;
1410 LIBNET_JOIN_OUT_DUMP_CTX(mem_ctx, r);
1415 /****************************************************************
1416 ****************************************************************/
1418 static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
1419 struct libnet_UnjoinCtx *r)
1423 if (!r->in.domain_sid) {
1425 if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
1426 libnet_unjoin_set_error_string(mem_ctx, r,
1427 "Unable to fetch domain sid: are we joined?");
1428 return WERR_SETUP_NOT_JOINED;
1430 r->in.domain_sid = sid_dup_talloc(mem_ctx, &sid);
1431 W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
1434 if (!r->in.dc_name) {
1435 struct DS_DOMAIN_CONTROLLER_INFO *info;
1436 status = dsgetdcname(mem_ctx,
1440 DS_DIRECTORY_SERVICE_REQUIRED |
1441 DS_WRITABLE_REQUIRED |
1444 if (!NT_STATUS_IS_OK(status)) {
1445 libnet_unjoin_set_error_string(mem_ctx, r,
1446 "failed to find DC for domain %s",
1448 get_friendly_nt_error_msg(status));
1449 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1452 r->in.dc_name = talloc_strdup(mem_ctx,
1453 info->domain_controller_name);
1454 W_ERROR_HAVE_NO_MEMORY(r->in.dc_name);
1457 status = libnet_join_unjoindomain_rpc(mem_ctx, r);
1458 if (!NT_STATUS_IS_OK(status)) {
1459 libnet_unjoin_set_error_string(mem_ctx, r,
1460 "failed to disable machine account via rpc: %s",
1461 get_friendly_nt_error_msg(status));
1462 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1463 return WERR_SETUP_NOT_JOINED;
1465 return ntstatus_to_werror(status);
1468 r->out.disabled_machine_account = true;
1471 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) {
1472 ADS_STATUS ads_status;
1473 libnet_unjoin_connect_ads(mem_ctx, r);
1474 ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r);
1475 if (!ADS_ERR_OK(ads_status)) {
1476 libnet_unjoin_set_error_string(mem_ctx, r,
1477 "failed to remove machine account from AD: %s",
1478 ads_errstr(ads_status));
1480 r->out.deleted_machine_account = true;
1482 r->out.dns_domain_name = talloc_strdup(mem_ctx,
1483 r->in.ads->server.realm);
1484 W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name);
1487 #endif /* WITH_ADS */
1489 libnet_join_unjoindomain_remove_secrets(mem_ctx, r);
1494 /****************************************************************
1495 ****************************************************************/
1497 static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
1498 struct libnet_UnjoinCtx *r)
1500 if (!r->in.domain_name) {
1501 libnet_unjoin_set_error_string(mem_ctx, r,
1502 "No domain name defined");
1503 return WERR_INVALID_PARAM;
1506 if (r->in.modify_config && !lp_config_backend_is_registry()) {
1507 return WERR_NOT_SUPPORTED;
1510 if (!secrets_init()) {
1511 libnet_unjoin_set_error_string(mem_ctx, r,
1512 "Unable to open secrets database");
1513 return WERR_CAN_NOT_COMPLETE;
1519 /****************************************************************
1520 ****************************************************************/
1522 static WERROR libnet_unjoin_post_processing(TALLOC_CTX *mem_ctx,
1523 struct libnet_UnjoinCtx *r)
1525 saf_delete(r->out.netbios_domain_name);
1526 saf_delete(r->out.dns_domain_name);
1528 return libnet_unjoin_config(r);
1531 /****************************************************************
1532 ****************************************************************/
1534 WERROR libnet_Unjoin(TALLOC_CTX *mem_ctx,
1535 struct libnet_UnjoinCtx *r)
1540 LIBNET_UNJOIN_IN_DUMP_CTX(mem_ctx, r);
1543 werr = libnet_unjoin_pre_processing(mem_ctx, r);
1544 if (!W_ERROR_IS_OK(werr)) {
1548 if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE) {
1549 werr = libnet_DomainUnjoin(mem_ctx, r);
1550 if (!W_ERROR_IS_OK(werr)) {
1551 libnet_unjoin_config(r);
1556 werr = libnet_unjoin_post_processing(mem_ctx, r);
1557 if (!W_ERROR_IS_OK(werr)) {
1562 r->out.result = werr;
1565 LIBNET_UNJOIN_OUT_DUMP_CTX(mem_ctx, r);