From b581ad2208ce15e3289fed9f98cb03d20adf90ca Mon Sep 17 00:00:00 2001 From: Jim McDonough Date: Sun, 21 Jun 2009 07:47:19 -0400 Subject: [PATCH] Don't require "Modify property" perms to unjoin bug #6481) "net ads leave" stopped working when "modify properties" permissions were not granted (meaning you had to be allowed to disable the account that you were about to delete). Libnetapi should not delete machine accounts, as this does not happen on win32. The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means "disable" (both in practice and docs). However, to keep the functionality in "net ads leave", we will still try to do the delete. If this fails, we try to do the disable. Additionally, it is possible in windows to not disable or delete the account, but just tell the local machine that it is no longer in the account. libnet can now do this as well. --- source/lib/netapi/joindomain.c | 1 + source/libnet/libnet_join.c | 49 ++++++++++++++++++++++--------- source/librpc/gen_ndr/libnet_join.h | 1 + source/librpc/gen_ndr/ndr_libnet_join.c | 1 + source/librpc/idl/libnet_join.idl | 1 + source/utils/net_ads.c | 11 ++++++- 6 files changed, 48 insertions(+), 16 deletions(-) diff --git a/source/lib/netapi/joindomain.c b/source/lib/netapi/joindomain.c index 66f7cfb..c204a80 100644 --- a/source/lib/netapi/joindomain.c +++ b/source/lib/netapi/joindomain.c @@ -209,6 +209,7 @@ WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx, u->in.domain_name = domain; u->in.unjoin_flags = r->in.unjoin_flags; + u->in.delete_machine_account = false; u->in.modify_config = true; u->in.debug = true; diff --git a/source/libnet/libnet_join.c b/source/libnet/libnet_join.c index c13ac9b..dc2b040 100644 --- a/source/libnet/libnet_join.c +++ b/source/libnet/libnet_join.c @@ -1835,6 +1835,12 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx, W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid); } + if (!(r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) && + !r->in.delete_machine_account) { + libnet_join_unjoindomain_remove_secrets(mem_ctx, r); + return WERR_OK; + } + if (!r->in.dc_name) { struct netr_DsRGetDCNameInfo *info; const char *dc; @@ -1860,21 +1866,12 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx, W_ERROR_HAVE_NO_MEMORY(r->in.dc_name); } - status = libnet_join_unjoindomain_rpc(mem_ctx, r); - if (!NT_STATUS_IS_OK(status)) { - libnet_unjoin_set_error_string(mem_ctx, r, - "failed to disable machine account via rpc: %s", - get_friendly_nt_error_msg(status)); - if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { - return WERR_SETUP_NOT_JOINED; - } - return ntstatus_to_werror(status); - } - - r->out.disabled_machine_account = true; - #ifdef WITH_ADS - if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) { + /* for net ads leave, try to delete the account. If it works, + no sense in disabling. If it fails, we can still try to + disable it. jmcd */ + + if (r->in.delete_machine_account) { ADS_STATUS ads_status; libnet_unjoin_connect_ads(mem_ctx, r); ads_status = libnet_unjoin_remove_machine_acct(mem_ctx, r); @@ -1888,10 +1885,34 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx, r->out.dns_domain_name = talloc_strdup(mem_ctx, r->in.ads->server.realm); W_ERROR_HAVE_NO_MEMORY(r->out.dns_domain_name); + libnet_join_unjoindomain_remove_secrets(mem_ctx, r); + return WERR_OK; } } #endif /* WITH_ADS */ + /* The WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE flag really means + "disable". */ + if (r->in.unjoin_flags & WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE) { + status = libnet_join_unjoindomain_rpc(mem_ctx, r); + if (!NT_STATUS_IS_OK(status)) { + libnet_unjoin_set_error_string(mem_ctx, r, + "failed to disable machine account via rpc: %s", + get_friendly_nt_error_msg(status)); + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { + return WERR_SETUP_NOT_JOINED; + } + return ntstatus_to_werror(status); + } + + r->out.disabled_machine_account = true; + r->out.dns_domain_name = talloc_strdup(mem_ctx, + r->in.ads->server.realm); + } + + /* If disable succeeded or was not requested at all, we + should be getting rid of our end of things */ + libnet_join_unjoindomain_remove_secrets(mem_ctx, r); return WERR_OK; diff --git a/source/librpc/gen_ndr/libnet_join.h b/source/librpc/gen_ndr/libnet_join.h index e5ec438..0de7132 100644 --- a/source/librpc/gen_ndr/libnet_join.h +++ b/source/librpc/gen_ndr/libnet_join.h @@ -56,6 +56,7 @@ struct libnet_UnjoinCtx { const char * admin_password; const char * machine_password; uint32_t unjoin_flags; + uint8_t delete_machine_account; uint8_t modify_config; struct dom_sid *domain_sid;/* [ref] */ struct ads_struct *ads;/* [ref] */ diff --git a/source/librpc/gen_ndr/ndr_libnet_join.c b/source/librpc/gen_ndr/ndr_libnet_join.c index 753859f..a550cd6 100644 --- a/source/librpc/gen_ndr/ndr_libnet_join.c +++ b/source/librpc/gen_ndr/ndr_libnet_join.c @@ -87,6 +87,7 @@ _PUBLIC_ void ndr_print_libnet_UnjoinCtx(struct ndr_print *ndr, const char *name ndr_print_ptr(ndr, "machine_password", r->in.machine_password); #endif ndr_print_wkssvc_joinflags(ndr, "unjoin_flags", r->in.unjoin_flags); + ndr_print_uint8(ndr, "delete_machine_account", r->in.delete_machine_account); ndr_print_uint8(ndr, "modify_config", r->in.modify_config); ndr_print_ptr(ndr, "domain_sid", r->in.domain_sid); ndr->depth++; diff --git a/source/librpc/idl/libnet_join.idl b/source/librpc/idl/libnet_join.idl index 7f6e346..93b1f09 100644 --- a/source/librpc/idl/libnet_join.idl +++ b/source/librpc/idl/libnet_join.idl @@ -51,6 +51,7 @@ interface libnetjoin [in] string admin_password, [in] string machine_password, [in] wkssvc_joinflags unjoin_flags, + [in] boolean8 delete_machine_account, [in] boolean8 modify_config, [in] dom_sid *domain_sid, [in] ads_struct *ads, diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index a023a11..6c6e805 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -835,8 +835,12 @@ static int net_ads_leave(int argc, const char **argv) r->in.admin_account = opt_user_name; r->in.admin_password = net_prompt_pass(opt_user_name); r->in.modify_config = lp_config_backend_is_registry(); + + /* Try to delete it, but if that fails, disable it. The + WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */ r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE | WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE; + r->in.delete_machine_account = true; werr = libnet_Unjoin(ctx, r); if (!W_ERROR_IS_OK(werr)) { @@ -846,7 +850,7 @@ static int net_ads_leave(int argc, const char **argv) goto done; } - if (W_ERROR_IS_OK(werr)) { + if (r->out.deleted_machine_account) { d_printf("Deleted account for '%s' in realm '%s'\n", r->in.machine_name, r->out.dns_domain_name); goto done; @@ -860,7 +864,10 @@ static int net_ads_leave(int argc, const char **argv) goto done; } - d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n", + /* Based on what we requseted, we shouldn't get here, but if + we did, it means the secrets were removed, and therefore + we have left the domain */ + d_fprintf(stderr, "Machine '%s' Left domain '%s'\n", r->in.machine_name, r->out.dns_domain_name); done: -- 1.6.3.2