#include "includes.h"
#include "rpc_server/dcerpc_server.h"
+#include "rpc_server/common/common.h"
#include "auth/auth.h"
#include "auth/auth_sam_reply.h"
#include "dsdb/samdb/samdb.h"
#include "librpc/gen_ndr/ndr_irpc.h"
#include "librpc/gen_ndr/ndr_winbind.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
+#include "librpc/rpc/server/netlogon/schannel_util.h"
#include "lib/socket/netif.h"
-#include "rpc_server/common/sid_helper.h"
#include "lib/util/util_str_escape.h"
+#include "lib/param/loadparm.h"
-#define DCESRV_INTERFACE_NETLOGON_BIND(call, iface) \
- dcesrv_interface_netlogon_bind(call, iface)
+#define DCESRV_INTERFACE_NETLOGON_BIND(context, iface) \
+ dcesrv_interface_netlogon_bind(context, iface)
+
+#undef strcasecmp
/*
* This #define allows the netlogon interface to accept invalid
*/
#define DCESRV_INTERFACE_NETLOGON_FLAGS DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED
-static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_call_state *dce_call,
+static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context *context,
const struct dcesrv_interface *iface)
{
- return dcesrv_interface_bind_reject_connect(dce_call, iface);
-}
+ struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx;
+ bool global_allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx);
+ bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx);
+ int schannel = lpcfg_server_schannel(lp_ctx);
+ bool schannel_global_required = (schannel == true);
+ bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx);
+ static bool warned_global_nt4_once = false;
+ static bool warned_global_md5_once = false;
+ static bool warned_global_schannel_once = false;
+ static bool warned_global_seal_once = false;
-struct netlogon_server_pipe_state {
- struct netr_Credential client_challenge;
- struct netr_Credential server_challenge;
-};
+ if (global_allow_nt4_crypto && !warned_global_nt4_once) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ D_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'allow nt4 crypto = no' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_nt4_once = true;
+ }
+
+ if (!global_reject_md5_client && !warned_global_md5_once) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ D_ERR("CVE-2022-38023: "
+ "Please configure 'reject md5 clients = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_md5_once = true;
+ }
+
+ if (!schannel_global_required && !warned_global_schannel_once) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ D_ERR("CVE-2020-1472(ZeroLogon): "
+ "Please configure 'server schannel = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n");
+ warned_global_schannel_once = true;
+ }
+
+ if (!global_require_seal && !warned_global_seal_once) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ D_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'server schannel require seal = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_seal_once = true;
+ }
+
+ return dcesrv_interface_bind_reject_connect(context, iface);
+}
static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_ServerReqChallenge *r)
{
- struct netlogon_server_pipe_state *pipe_state =
- talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
+ struct netlogon_server_pipe_state *pipe_state = NULL;
NTSTATUS ntstatus;
ZERO_STRUCTP(r->out.return_credentials);
- if (pipe_state) {
- talloc_free(pipe_state);
- dce_call->context->private_data = NULL;
- }
+ pipe_state = dcesrv_iface_state_find_conn(dce_call,
+ NETLOGON_SERVER_PIPE_STATE_MAGIC,
+ struct netlogon_server_pipe_state);
+ TALLOC_FREE(pipe_state);
- pipe_state = talloc(dce_call->context, struct netlogon_server_pipe_state);
- NT_STATUS_HAVE_NO_MEMORY(pipe_state);
+ pipe_state = talloc_zero(dce_call,
+ struct netlogon_server_pipe_state);
+ if (pipe_state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
pipe_state->client_challenge = *r->in.credentials;
- generate_random_buffer(pipe_state->server_challenge.data,
- sizeof(pipe_state->server_challenge.data));
+ netlogon_creds_random_challenge(&pipe_state->server_challenge);
*r->out.return_credentials = pipe_state->server_challenge;
- dce_call->context->private_data = pipe_state;
+ ntstatus = dcesrv_iface_state_store_conn(dce_call,
+ NETLOGON_SERVER_PIPE_STATE_MAGIC,
+ pipe_state);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ return ntstatus;
+ }
ntstatus = schannel_save_challenge(dce_call->conn->dce_ctx->lp_ctx,
&pipe_state->client_challenge,
&pipe_state->server_challenge,
r->in.computer_name);
if (!NT_STATUS_IS_OK(ntstatus)) {
+ TALLOC_FREE(pipe_state);
return ntstatus;
}
return NT_STATUS_OK;
}
+static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ struct dcesrv_call_state *dce_call,
+ struct netr_ServerAuthenticate3 *r,
+ struct netlogon_server_pipe_state *pipe_state,
+ uint32_t negotiate_flags,
+ const char *trust_account_in_db,
+ NTSTATUS orig_status)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ bool global_allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx);
+ bool account_allow_nt4_crypto = global_allow_nt4_crypto;
+ const char *explicit_nt4_opt = NULL;
+ bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx);
+ bool account_reject_md5_client = global_reject_md5_client;
+ const char *explicit_md5_opt = NULL;
+ bool reject_des_client;
+ bool allow_nt4_crypto;
+ bool reject_md5_client;
+ bool need_des = true;
+ bool need_md5 = true;
+ int CVE_2022_38023_warn_level = lpcfg_parm_int(lp_ctx, NULL,
+ "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR);
+ int CVE_2022_38023_error_level = lpcfg_parm_int(lp_ctx, NULL,
+ "CVE_2022_38023", "error_debug_level", DBGLVL_ERR);
+
+ /*
+ * We don't use lpcfg_parm_bool(), as we
+ * need the explicit_opt pointer in order to
+ * adjust the debug messages.
+ */
+
+ if (trust_account_in_db != NULL) {
+ explicit_nt4_opt = lpcfg_get_parametric(lp_ctx,
+ NULL,
+ "allow nt4 crypto",
+ trust_account_in_db);
+ }
+ if (explicit_nt4_opt != NULL) {
+ account_allow_nt4_crypto = lp_bool(explicit_nt4_opt);
+ }
+ allow_nt4_crypto = account_allow_nt4_crypto;
+ if (trust_account_in_db != NULL) {
+ explicit_md5_opt = lpcfg_get_parametric(lp_ctx,
+ NULL,
+ "server reject md5 schannel",
+ trust_account_in_db);
+ }
+ if (explicit_md5_opt != NULL) {
+ account_reject_md5_client = lp_bool(explicit_md5_opt);
+ }
+ reject_md5_client = account_reject_md5_client;
+
+ reject_des_client = !allow_nt4_crypto;
+
+ /*
+ * If weak crypto is disabled, do not announce that we support RC4.
+ */
+ if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
+ /* Without RC4 and DES we require AES */
+ reject_des_client = true;
+ reject_md5_client = true;
+ }
+
+ if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
+ need_des = false;
+ reject_des_client = false;
+ }
+
+ if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ need_des = false;
+ need_md5 = false;
+ reject_des_client = false;
+ reject_md5_client = false;
+ }
+
+ if (reject_des_client || reject_md5_client) {
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
+ if (CVE_2022_38023_error_level < DBGLVL_NOTICE) {
+ CVE_2022_38023_error_level = DBGLVL_NOTICE;
+ }
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: "
+ "client_account[%s] computer_name[%s] "
+ "schannel_type[%u] "
+ "client_negotiate_flags[0x%x] "
+ "%s%s%s "
+ "NT_STATUS_DOWNGRADE_DETECTED "
+ "WEAK_CRYPTO_DISALLOWED\n",
+ log_escape(frame, r->in.account_name),
+ log_escape(frame, r->in.computer_name),
+ r->in.secure_channel_type,
+ (unsigned)*r->in.negotiate_flags,
+ trust_account_in_db ? "real_account[" : "",
+ trust_account_in_db ? trust_account_in_db : "",
+ trust_account_in_db ? "]" : ""));
+ goto return_downgrade;
+ }
+
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: "
+ "client_account[%s] computer_name[%s] "
+ "schannel_type[%u] "
+ "client_negotiate_flags[0x%x] "
+ "%s%s%s "
+ "NT_STATUS_DOWNGRADE_DETECTED "
+ "reject_des[%u] reject_md5[%u]\n",
+ log_escape(frame, r->in.account_name),
+ log_escape(frame, r->in.computer_name),
+ r->in.secure_channel_type,
+ (unsigned)*r->in.negotiate_flags,
+ trust_account_in_db ? "real_account[" : "",
+ trust_account_in_db ? trust_account_in_db : "",
+ trust_account_in_db ? "]" : "",
+ reject_des_client,
+ reject_md5_client));
+ if (trust_account_in_db == NULL) {
+ goto return_downgrade;
+ }
+
+ if (reject_md5_client && explicit_md5_opt == NULL) {
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: Check if option "
+ "'server reject md5 schannel:%s = no' "
+ "might be needed for a legacy client.\n",
+ trust_account_in_db));
+ }
+ if (reject_des_client && explicit_nt4_opt == NULL) {
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: Check if option "
+ "'allow nt4 crypto:%s = yes' "
+ "might be needed for a legacy client.\n",
+ trust_account_in_db));
+ }
+
+return_downgrade:
+ /*
+ * Here we match Windows 2012 and return no flags.
+ */
+ *r->out.negotiate_flags = 0;
+ TALLOC_FREE(frame);
+ return NT_STATUS_DOWNGRADE_DETECTED;
+ }
+
+ /*
+ * This talloc_free is important to prevent re-use of the
+ * challenge. We have to delay it this far due to NETApp
+ * servers per:
+ * https://bugzilla.samba.org/show_bug.cgi?id=11291
+ */
+ TALLOC_FREE(pipe_state);
+
+ /*
+ * At this point we must also cleanup the TDB cache
+ * entry, if we fail the client needs to call
+ * netr_ServerReqChallenge again.
+ *
+ * Note: this handles a non existing record just fine,
+ * the r->in.computer_name might not be the one used
+ * in netr_ServerReqChallenge(), but we are trying to
+ * just tidy up the normal case to prevent re-use.
+ */
+ schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx,
+ r->in.computer_name);
+
+ /*
+ * According to Microsoft (see bugid #6099)
+ * Windows 7 looks at the negotiate_flags
+ * returned in this structure *even if the
+ * call fails with access denied!
+ */
+ *r->out.negotiate_flags = negotiate_flags;
+
+ if (!NT_STATUS_IS_OK(orig_status) || trust_account_in_db == NULL) {
+ return orig_status;
+ }
+
+ if (global_reject_md5_client && account_reject_md5_client && explicit_md5_opt) {
+ D_INFO("CVE-2022-38023: Check if option "
+ "'server reject md5 schannel:%s = yes' not needed!?\n",
+ trust_account_in_db);
+ } else if (need_md5 && !account_reject_md5_client && explicit_md5_opt) {
+ D_INFO("CVE-2022-38023: Check if option "
+ "'server reject md5 schannel:%s = no' "
+ "still needed for a legacy client.\n",
+ trust_account_in_db);
+ } else if (need_md5 && explicit_md5_opt == NULL) {
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: Check if option "
+ "'server reject md5 schannel:%s = no' "
+ "might be needed for a legacy client.\n",
+ trust_account_in_db));
+ } else if (!account_reject_md5_client && explicit_md5_opt) {
+ DEBUG(CVE_2022_38023_warn_level, (
+ "CVE-2022-38023: Check if option "
+ "'server reject md5 schannel:%s = no' not needed!?\n",
+ trust_account_in_db));
+ }
+
+ if (!global_allow_nt4_crypto && !account_allow_nt4_crypto && explicit_nt4_opt) {
+ D_INFO("CVE-2022-38023: Check if option "
+ "'allow nt4 crypto:%s = no' not needed!?\n",
+ trust_account_in_db);
+ } else if (need_des && account_allow_nt4_crypto && explicit_nt4_opt) {
+ D_INFO("CVE-2022-38023: Check if option "
+ "'allow nt4 crypto:%s = yes' "
+ "still needed for a legacy client.\n",
+ trust_account_in_db);
+ } else if (need_des && explicit_nt4_opt == NULL) {
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: Check if option "
+ "'allow nt4 crypto:%s = yes' "
+ "might be needed for a legacy client.\n",
+ trust_account_in_db));
+ } else if (account_allow_nt4_crypto && explicit_nt4_opt) {
+ DEBUG(CVE_2022_38023_warn_level, (
+ "CVE-2022-38023: Check if option "
+ "'allow nt4 crypto:%s = yes' not needed!?\n",
+ trust_account_in_db));
+ }
+
+ return orig_status;
+}
+
/*
* Do the actual processing of a netr_ServerAuthenticate3 message.
* called from dcesrv_netr_ServerAuthenticate3, which handles the logging.
const char **trust_account_in_db,
struct dom_sid **sid)
{
- struct netlogon_server_pipe_state *pipe_state =
- talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
+ struct netlogon_server_pipe_state *pipe_state = NULL;
bool challenge_valid = false;
struct netlogon_server_pipe_state challenge;
struct netlogon_creds_CredentialState *creds;
"objectSid", "samAccountName", NULL};
uint32_t server_flags = 0;
uint32_t negotiate_flags = 0;
- bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(dce_call->conn->dce_ctx->lp_ctx);
- bool reject_des_client = !allow_nt4_crypto;
- bool reject_md5_client = lpcfg_reject_md5_clients(dce_call->conn->dce_ctx->lp_ctx);
- int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
- bool reject_none_rpc = (schannel == true);
ZERO_STRUCTP(r->out.return_credentials);
+ *r->out.negotiate_flags = 0;
*r->out.rid = 0;
+ pipe_state = dcesrv_iface_state_find_conn(dce_call,
+ NETLOGON_SERVER_PIPE_STATE_MAGIC,
+ struct netlogon_server_pipe_state);
if (pipe_state != NULL) {
- dce_call->context->private_data = NULL;
-
/*
* If we had a challenge remembered on the connection
* consider this for usage. This can't be cleanup
NETLOGON_NEG_AUTHENTICATED_RPC_LSASS |
NETLOGON_NEG_AUTHENTICATED_RPC;
- negotiate_flags = *r->in.negotiate_flags & server_flags;
-
- if (negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
- reject_none_rpc = false;
- }
-
- if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
- reject_des_client = false;
- }
-
- if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
- reject_des_client = false;
- reject_md5_client = false;
- }
-
- if (reject_des_client || reject_md5_client) {
- /*
- * Here we match Windows 2012 and return no flags.
- */
- *r->out.negotiate_flags = 0;
- return NT_STATUS_DOWNGRADE_DETECTED;
- }
-
- /*
- * This talloc_free is important to prevent re-use of the
- * challenge. We have to delay it this far due to NETApp
- * servers per:
- * https://bugzilla.samba.org/show_bug.cgi?id=11291
- */
- TALLOC_FREE(pipe_state);
-
- /*
- * At this point we must also cleanup the TDB cache
- * entry, if we fail the client needs to call
- * netr_ServerReqChallenge again.
- *
- * Note: this handles a non existing record just fine,
- * the r->in.computer_name might not be the one used
- * in netr_ServerReqChallenge(), but we are trying to
- * just tidy up the normal case to prevent re-use.
- */
- schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx,
- r->in.computer_name);
-
/*
- * According to Microsoft (see bugid #6099)
- * Windows 7 looks at the negotiate_flags
- * returned in this structure *even if the
- * call fails with access denied!
+ * If weak crypto is disabled, do not announce that we support RC4.
*/
- *r->out.negotiate_flags = negotiate_flags;
-
- if (reject_none_rpc) {
- /* schannel must be used, but client did not offer it. */
- DEBUG(0,("%s: schannel required but client failed "
- "to offer it. Client was %s\n",
- __func__,
- log_escape(mem_ctx, r->in.account_name)));
- return NT_STATUS_ACCESS_DENIED;
+ if (lpcfg_weak_crypto(dce_call->conn->dce_ctx->lp_ctx) ==
+ SAMBA_WEAK_CRYPTO_DISALLOWED) {
+ server_flags &= ~NETLOGON_NEG_ARCFOUR;
}
+ negotiate_flags = *r->in.negotiate_flags & server_flags;
+
switch (r->in.secure_channel_type) {
case SEC_CHAN_WKSTA:
case SEC_CHAN_DNS_DOMAIN:
case SEC_CHAN_RODC:
break;
case SEC_CHAN_NULL:
- return NT_STATUS_INVALID_PARAMETER;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_INVALID_PARAMETER);
default:
DEBUG(1, ("Client asked for an invalid secure channel type: %d\n",
r->in.secure_channel_type));
- return NT_STATUS_INVALID_PARAMETER;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_INVALID_PARAMETER);
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
- return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_INVALID_SYSTEM_SERVICE);
}
if (r->in.secure_channel_type == SEC_CHAN_DOMAIN ||
encoded_name = ldb_binary_encode_string(mem_ctx,
r->in.account_name);
if (encoded_name == NULL) {
- return NT_STATUS_NO_MEMORY;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_MEMORY);
}
len = strlen(encoded_name);
if (len < 2) {
- return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_TRUST_SAM_ACCOUNT);
}
if (require_trailer && encoded_name[len - 1] != trailer) {
- return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_TRUST_SAM_ACCOUNT);
}
encoded_name[len - 1] = '\0';
"but there's no tdo for [%s] => [%s] \n",
log_escape(mem_ctx, r->in.account_name),
encoded_name));
- return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_TRUST_SAM_ACCOUNT);
}
if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ nt_status);
}
nt_status = dsdb_trust_get_incoming_passwords(tdo_msg, mem_ctx,
&curNtHash,
&prevNtHash);
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) {
- return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_TRUST_SAM_ACCOUNT);
}
if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ nt_status);
}
flatname = ldb_msg_find_attr_as_string(tdo_msg, "flatName", NULL);
if (flatname == NULL) {
- return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_TRUST_SAM_ACCOUNT);
}
*trust_account_for_search = talloc_asprintf(mem_ctx, "%s$", flatname);
if (*trust_account_for_search == NULL) {
- return NT_STATUS_NO_MEMORY;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_MEMORY);
}
} else {
*trust_account_for_search = r->in.account_name;
if (num_records == 0) {
DEBUG(3,("Couldn't find user [%s] in samdb.\n",
log_escape(mem_ctx, r->in.account_name)));
- return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_NO_TRUST_SAM_ACCOUNT);
}
if (num_records > 1) {
DEBUG(0,("Found %d records matching user [%s]\n",
num_records,
log_escape(mem_ctx, r->in.account_name)));
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_INTERNAL_DB_CORRUPTION);
}
*trust_account_in_db = ldb_msg_find_attr_as_string(msgs[0],
if (*trust_account_in_db == NULL) {
DEBUG(0,("No samAccountName returned in record matching user [%s]\n",
r->in.account_name));
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ return dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ NULL, /* trust_account_in_db */
+ NT_STATUS_INTERNAL_DB_CORRUPTION);
+ }
+
+ nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade(
+ dce_call, r, pipe_state, negotiate_flags,
+ *trust_account_in_db,
+ NT_STATUS_OK);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
}
-
+
user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0);
if (user_account_control & UF_ACCOUNTDISABLE) {
if (!(user_account_control & UF_INTERDOMAIN_TRUST_ACCOUNT)) {
nt_status = samdb_result_passwords_no_lockout(mem_ctx,
dce_call->conn->dce_ctx->lp_ctx,
- msgs[0], NULL, &curNtHash);
+ msgs[0], &curNtHash);
if (!NT_STATUS_IS_OK(nt_status)) {
return NT_STATUS_ACCESS_DENIED;
}
struct dom_sid *sid = NULL;
const char *trust_account_for_search = NULL;
const char *trust_account_in_db = NULL;
+ struct imessaging_context *imsg_ctx =
+ dcesrv_imessaging_context(dce_call->conn);
struct auth_usersupplied_info ui = {
.local_host = dce_call->conn->local_address,
.remote_host = dce_call->conn->remote_address,
ui.netlogon_trust_account.account_name = trust_account_in_db;
ui.mapped.account_name = trust_account_for_search;
log_authentication_event(
- dce_call->conn->msg_ctx,
+ imsg_ctx,
dce_call->conn->dce_ctx->lp_ctx,
NULL,
&ui,
status,
lpcfg_workgroup(dce_call->conn->dce_ctx->lp_ctx),
trust_account_in_db,
- NULL,
- sid);
+ sid,
+ NULL /* client_audit_info */,
+ NULL /* server_audit_info */);
return status;
}
return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3);
}
-/*
- * NOTE: The following functions are nearly identical to the ones available in
- * source3/rpc_server/srv_nelog_nt.c
- * The reason we keep 2 copies is that they use different structures to
- * represent the auth_info and the decrpc pipes.
- */
-static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call,
- TALLOC_CTX *mem_ctx,
- const char *computer_name,
- struct netr_Authenticator *received_authenticator,
- struct netr_Authenticator *return_authenticator,
- struct netlogon_creds_CredentialState **creds_out)
-{
- NTSTATUS nt_status;
- int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
- bool schannel_global_required = (schannel == true);
-
- if (schannel_global_required) {
- if (dce_call->conn->auth_state.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
- DBG_ERR("[%s] is not using schannel\n",
- computer_name);
- return NT_STATUS_ACCESS_DENIED;
- }
- }
-
- nt_status = schannel_check_creds_state(mem_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- computer_name,
- received_authenticator,
- return_authenticator,
- creds_out);
- return nt_status;
-}
-
/*
Change the machine account password for the currently connected
client. Supplies only the NT#.
{
struct netlogon_creds_CredentialState *creds;
struct ldb_context *sam_ctx;
- const char * const attrs[] = { "unicodePwd", NULL };
- struct ldb_message **res;
- struct samr_Password *oldNtHash;
NTSTATUS nt_status;
- int ret;
nt_status = dcesrv_netr_creds_server_step_check(dce_call,
mem_ctx,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
- netlogon_creds_des_decrypt(creds, r->in.new_password);
-
- /* fetch the old password hashes (the NT hash has to exist) */
-
- ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs,
- "(&(objectClass=user)(objectSid=%s))",
- ldap_encode_ndr_dom_sid(mem_ctx, creds->sid));
- if (ret != 1) {
- return NT_STATUS_WRONG_PASSWORD;
- }
-
- nt_status = samdb_result_passwords_no_lockout(mem_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- res[0], NULL, &oldNtHash);
- if (!NT_STATUS_IS_OK(nt_status) || !oldNtHash) {
- return NT_STATUS_WRONG_PASSWORD;
- }
+ nt_status = netlogon_creds_des_decrypt(creds, r->in.new_password);
+ NT_STATUS_NOT_OK_RETURN(nt_status);
/* Using the sid for the account as the key, set the password */
nt_status = samdb_set_password_sid(sam_ctx, mem_ctx,
creds->sid,
NULL, /* Don't have version */
NULL, /* Don't have plaintext */
- NULL, r->in.new_password,
- NULL, oldNtHash, /* Password change */
+ r->in.new_password,
+ DSDB_PASSWORD_CHECKED_AND_CORRECT, /* Password change */
NULL, NULL);
return nt_status;
}
{
struct netlogon_creds_CredentialState *creds;
struct ldb_context *sam_ctx;
- const char * const attrs[] = { "dBCSPwd", "unicodePwd", NULL };
- struct ldb_message **res;
- struct samr_Password *oldLmHash, *oldNtHash;
struct NL_PASSWORD_VERSION version = {};
const uint32_t *new_version = NULL;
NTSTATUS nt_status;
- DATA_BLOB new_password;
- int ret;
+ DATA_BLOB new_password = data_blob_null;
+ size_t confounder_len;
+ DATA_BLOB dec_blob = data_blob_null;
+ DATA_BLOB enc_blob = data_blob_null;
struct samr_CryptPassword password_buf;
nt_status = dcesrv_netr_creds_server_step_check(dce_call,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
SIVAL(password_buf.data, 512, r->in.new_password->length);
if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
- netlogon_creds_aes_decrypt(creds, password_buf.data, 516);
+ nt_status = netlogon_creds_aes_decrypt(creds,
+ password_buf.data,
+ 516);
} else {
- netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+ nt_status = netlogon_creds_arcfour_crypt(creds,
+ password_buf.data,
+ 516);
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
}
switch (creds->secure_channel_type) {
return NT_STATUS_WRONG_PASSWORD;
}
- /* fetch the old password hashes (at least one of both has to exist) */
+ /*
+ * Make sure the length field was encrypted,
+ * otherwise we are under attack.
+ */
+ if (new_password.length == r->in.new_password->length) {
+ DBG_WARNING("Length[%zu] field not encrypted\n",
+ new_password.length);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
- ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs,
- "(&(objectClass=user)(objectSid=%s))",
- ldap_encode_ndr_dom_sid(mem_ctx, creds->sid));
- if (ret != 1) {
+ /*
+ * We don't allow empty passwords for machine accounts.
+ */
+ if (new_password.length < 2) {
+ DBG_WARNING("Empty password Length[%zu]\n",
+ new_password.length);
return NT_STATUS_WRONG_PASSWORD;
}
- nt_status = samdb_result_passwords_no_lockout(mem_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- res[0], &oldLmHash, &oldNtHash);
- if (!NT_STATUS_IS_OK(nt_status) || (!oldLmHash && !oldNtHash)) {
+ /*
+ * Make sure the confounder part of CryptPassword
+ * buffer was encrypted, otherwise we are under attack.
+ */
+ confounder_len = 512 - new_password.length;
+ enc_blob = data_blob_const(r->in.new_password->data, confounder_len);
+ dec_blob = data_blob_const(password_buf.data, confounder_len);
+ if (confounder_len > 0 && data_blob_equal_const_time(&dec_blob, &enc_blob)) {
+ DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n",
+ confounder_len);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * Check that the password part was actually encrypted,
+ * otherwise we are under attack.
+ */
+ enc_blob = data_blob_const(r->in.new_password->data + confounder_len,
+ new_password.length);
+ dec_blob = data_blob_const(password_buf.data + confounder_len,
+ new_password.length);
+ if (data_blob_equal_const_time(&dec_blob, &enc_blob)) {
+ DBG_WARNING("Password buffer not encrypted Length[%zu]\n",
+ new_password.length);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * don't allow zero buffers
+ */
+ if (all_zero(new_password.data, new_password.length)) {
+ DBG_WARNING("Password zero buffer Length[%zu]\n",
+ new_password.length);
return NT_STATUS_WRONG_PASSWORD;
}
creds->sid,
new_version,
&new_password, /* we have plaintext */
- NULL, NULL,
- oldLmHash, oldNtHash, /* Password change */
+ NULL,
+ DSDB_PASSWORD_CHECKED_AND_CORRECT, /* Password change */
NULL, NULL);
return nt_status;
}
static NTSTATUS dcesrv_netr_LogonSamLogon_check(struct dcesrv_call_state *dce_call,
const struct netr_LogonSamLogonEx *r)
{
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
+
switch (r->in.logon_level) {
case NetlogonInteractiveInformation:
case NetlogonServiceInformation:
return NT_STATUS_INVALID_PARAMETER;
}
+ dcesrv_call_auth_info(dce_call, NULL, &auth_level);
+
switch (r->in.validation_level) {
case NetlogonValidationSamInfo4: /* 6 */
- if (dce_call->conn->auth_state.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
+ if (auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
return NT_STATUS_INVALID_PARAMETER;
}
break;
static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamLogon_base_state *state)
{
struct dcesrv_call_state *dce_call = state->dce_call;
+ struct imessaging_context *imsg_ctx =
+ dcesrv_imessaging_context(dce_call->conn);
TALLOC_CTX *mem_ctx = state->mem_ctx;
struct netr_LogonSamLogonEx *r = &state->r;
struct netlogon_creds_CredentialState *creds = state->creds;
struct auth_usersupplied_info *user_info = NULL;
NTSTATUS nt_status;
struct tevent_req *subreq = NULL;
+ enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+ dcesrv_call_auth_info(dce_call, &auth_type, &auth_level);
+
+ switch (dce_call->pkt.u.request.opnum) {
+ case NDR_NETR_LOGONSAMLOGON:
+ case NDR_NETR_LOGONSAMLOGONWITHFLAGS:
+ /*
+ * These already called dcesrv_netr_check_schannel()
+ * via dcesrv_netr_creds_server_step_check()
+ */
+ break;
+ case NDR_NETR_LOGONSAMLOGONEX:
+ default:
+ if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ nt_status = dcesrv_netr_check_schannel(dce_call,
+ creds,
+ auth_type,
+ auth_level,
+ dce_call->pkt.u.request.opnum);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+ break;
+ }
*r->out.authoritative = 1;
user_info->service_description = "SamLogon";
- netlogon_creds_decrypt_samlogon_logon(creds,
- r->in.logon_level,
- r->in.logon);
+ nt_status = netlogon_creds_decrypt_samlogon_logon(creds,
+ r->in.logon_level,
+ r->in.logon);
+ NT_STATUS_NOT_OK_RETURN(nt_status);
switch (r->in.logon_level) {
case NetlogonInteractiveInformation:
case NetlogonNetworkTransitiveInformation:
nt_status = auth_context_create_for_netlogon(mem_ctx,
- dce_call->event_ctx, dce_call->msg_ctx,
+ dce_call->event_ctx,
+ imsg_ctx,
dce_call->conn->dce_ctx->lp_ctx,
&auth_context);
NT_STATUS_NOT_OK_RETURN(nt_status);
user_info->netlogon_trust_account.sid
= creds->sid;
+ break;
default:
/* We do not need to set up the user_info in this case */
break;
NT_STATUS_HAVE_NO_MEMORY(user_info->password.hash.nt);
*user_info->password.hash.nt = r->in.logon->password->ntpassword;
+ user_info->logon_id
+ = r->in.logon->password->identity_info.logon_id;
+
break;
case NetlogonNetworkInformation:
case NetlogonNetworkTransitiveInformation:
user_info->password.response.lanman = data_blob_talloc(mem_ctx, r->in.logon->network->lm.data, r->in.logon->network->lm.length);
user_info->password.response.nt = data_blob_talloc(mem_ctx, r->in.logon->network->nt.data, r->in.logon->network->nt.length);
+ user_info->logon_id
+ = r->in.logon->network->identity_info.logon_id;
+
nt_status = NTLMv2_RESPONSE_verify_netlogon_creds(
user_info->client.account_name,
user_info->client.domain_name,
r->out.validation->generic = generic;
+ user_info->logon_id
+ = r->in.logon->generic->identity_info.logon_id;
+
irpc_handle = irpc_binding_handle_by_name(mem_ctx,
- dce_call->msg_ctx,
+ imsg_ctx,
"kdc_server",
&ndr_table_irpc);
if (irpc_handle == NULL) {
return NT_STATUS_OK;
}
- /* Until we get an implemetnation of these other packages */
+ /* Until we get an implementation of these other packages */
return NT_STATUS_INVALID_PARAMETER;
}
default:
case 2:
nt_status = auth_convert_user_info_dc_saminfo2(mem_ctx,
user_info_dc,
+ AUTH_INCLUDE_RESOURCE_GROUPS,
&sam2);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.result = nt_status;
case 3:
nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx,
user_info_dc,
- &sam3);
+ AUTH_INCLUDE_RESOURCE_GROUPS,
+ &sam3, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.result = nt_status;
dcesrv_netr_LogonSamLogon_base_reply(state);
case 6:
nt_status = auth_convert_user_info_dc_saminfo6(mem_ctx,
user_info_dc,
- &sam6);
+ AUTH_INCLUDE_RESOURCE_GROUPS,
+ &sam6, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.result = nt_status;
dcesrv_netr_LogonSamLogon_base_reply(state);
NTSTATUS status;
if (NT_STATUS_IS_OK(r->out.result)) {
- netlogon_creds_encrypt_samlogon_validation(state->creds,
- r->in.validation_level,
- r->out.validation);
+ status = netlogon_creds_encrypt_samlogon_validation(state->creds,
+ r->in.validation_level,
+ r->out.validation);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("netlogon_creds_encrypt_samlogon_validation() "
+ "failed - %s\n",
+ nt_errstr(status));
+ }
}
if (state->_r.lslex != NULL) {
return nt_status;
}
- if (dce_call->conn->auth_state.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
nt_status = dcesrv_netr_LogonSamLogon_base_call(state);
if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
static WERROR dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetDcName *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
const char * const attrs[] = { NULL };
struct ldb_context *sam_ctx;
struct ldb_message **res;
}
/*
- * TODO: Should we also varify that only valid
+ * TODO: Should we also verify that only valid
* netbios name characters are used?
*/
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
struct loadparm_context *lp_ctx = state->dce_call->conn->dce_ctx->lp_ctx;
struct auth_session_info *session_info =
dcesrv_call_session_info(state->dce_call);
+ struct imessaging_context *imsg_ctx =
+ dcesrv_imessaging_context(state->dce_call->conn);
enum security_user_level security_level;
struct dcerpc_binding_handle *irpc_handle;
struct tevent_req *subreq;
if (!ok) {
struct ldb_context *sam_ctx;
- sam_ctx = samdb_connect(
- state,
- state->dce_call->event_ctx,
- lp_ctx,
- system_session(lp_ctx),
- state->dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(state,
+ state->dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
}
irpc_handle = irpc_binding_handle_by_name(state,
- state->dce_call->msg_ctx,
+ imsg_ctx,
"winbind_server",
&ndr_table_winbind);
if (irpc_handle == NULL) {
static WERROR dcesrv_netr_GetAnyDCName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetAnyDCName *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct netr_DomainTrustList *trusts;
struct ldb_context *sam_ctx;
struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
r->in.domainname = lpcfg_workgroup(lp_ctx);
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
struct netlogon_creds_CredentialState *creds;
NTSTATUS status;
+ switch (r->in.query_level) {
+ case 1:
+ break;
+ case 2:
+ /*
+ * Until we know the details behind KB5028166
+ * just return DCERPC_NCA_S_FAULT_INVALID_TAG
+ * like an unpatched Windows Server.
+ */
+ FALL_THROUGH;
+ default:
+ /*
+ * There would not be a way to marshall the
+ * the response. Which would mean our final
+ * ndr_push would fail an we would return
+ * an RPC-level fault with DCERPC_FAULT_BAD_STUB_DATA.
+ *
+ * But it's important to match a Windows server
+ * especially before KB5028166, see also our bug #15418
+ * Otherwise Windows client would stop talking to us.
+ */
+ DCESRV_FAULT(DCERPC_NCA_S_FAULT_INVALID_TAG);
+ }
+
status = dcesrv_netr_creds_server_step_check(dce_call,
mem_ctx,
r->in.computer_name,
}
NT_STATUS_NOT_OK_RETURN(status);
- if (r->in.query_level != 1) {
- return NT_STATUS_NOT_SUPPORTED;
- }
-
r->out.capabilities->server_capabilities = creds->negotiate_flags;
return NT_STATUS_OK;
static WERROR dcesrv_netr_DsRGetSiteName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsRGetSiteName *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct ldb_context *sam_ctx;
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
ZERO_STRUCTP(info);
if (is_trust_list) {
- struct netr_trust_extension *tei = NULL;
+ struct netr_trust_extension *te = NULL;
+ struct netr_trust_extension_info *tei = NULL;
/* w2k8 only fills this on trusted domains */
- tei = talloc_zero(mem_ctx, struct netr_trust_extension);
- if (tei == NULL) {
+ te = talloc_zero(mem_ctx, struct netr_trust_extension);
+ if (te == NULL) {
return NT_STATUS_NO_MEMORY;
}
+ tei = &te->info;
tei->flags |= NETR_TRUST_FLAG_PRIMARY;
/*
*/
tei->trust_attributes = 0;
- info->trust_extension.info = tei;
- info->trust_extension.length = 16;
+ info->trust_extension.info = te;
}
if (is_trust_list) {
const struct lsa_TrustDomainInfoInfoEx *tdo,
struct netr_OneDomainInfo *info)
{
- struct netr_trust_extension *tei = NULL;
+ struct netr_trust_extension *te = NULL;
+ struct netr_trust_extension_info *tei = NULL;
ZERO_STRUCTP(info);
/* w2k8 only fills this on trusted domains */
- tei = talloc_zero(mem_ctx, struct netr_trust_extension);
- if (tei == NULL) {
+ te = talloc_zero(mem_ctx, struct netr_trust_extension);
+ if (te == NULL) {
return NT_STATUS_NO_MEMORY;
}
+ tei = &te->info;
if (tdo->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
tei->flags |= NETR_TRUST_FLAG_INBOUND;
tei->trust_type = tdo->trust_type;
tei->trust_attributes = tdo->trust_attributes;
- info->trust_extension.info = tei;
- info->trust_extension.length = 16;
+ info->trust_extension.info = te;
info->domainname.string = tdo->netbios_name.string;
if (tdo->trust_type != LSA_TRUST_TYPE_DOWNLEVEL) {
};
const char * const attrs2[] = { "sAMAccountName", "dNSHostName",
"msDS-SupportedEncryptionTypes", NULL };
- const char *sam_account_name, *old_dns_hostname, *prefix1, *prefix2;
+ const char *sam_account_name, *old_dns_hostname;
struct ldb_context *sam_ctx;
const struct GUID *our_domain_guid = NULL;
struct lsa_TrustDomainInfoInfoEx *our_tdo = NULL;
struct ldb_dn *workstation_dn;
struct netr_DomainInformation *domain_info;
struct netr_LsaPolicyInformation *lsa_policy_info;
+ struct auth_session_info *workstation_session_info = NULL;
uint32_t default_supported_enc_types = 0xFFFFFFFF;
bool update_dns_hostname = true;
int ret, i;
frame);
local = tsocket_address_string(dce_call->conn->local_address,
frame);
- DBG_ERR(("Bad credentials - "
- "computer[%s] remote[%s] local[%s]\n"),
+ DBG_ERR("Bad credentials - "
+ "computer[%s] remote[%s] local[%s]\n",
log_escape(frame, r->in.computer_name),
remote,
local);
}
NT_STATUS_NOT_OK_RETURN(status);
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ /* We want to avoid connecting as system. */
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
dom_sid_string(mem_ctx, creds->sid));
NT_STATUS_HAVE_NO_MEMORY(workstation_dn);
+ /* Get the workstation's session info from the database. */
+ status = authsam_get_session_info_principal(mem_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
+ sam_ctx,
+ NULL, /* principal */
+ workstation_dn,
+ 0, /* session_info_flags */
+ &workstation_session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * Reconnect to samdb as the workstation, now that we have its
+ * session info. We do this so the database update can be
+ * attributed to the workstation account in the audit logs --
+ * otherwise it might be incorrectly attributed to
+ * SID_NT_ANONYMOUS.
+ */
+ sam_ctx = dcesrv_samdb_connect_session_info(mem_ctx,
+ dce_call,
+ workstation_session_info,
+ workstation_session_info);
+ if (sam_ctx == NULL) {
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
+ }
+
/* Lookup for attributes in workstation object */
ret = gendb_search_dn(sam_ctx, mem_ctx, workstation_dn, &res1,
attrs2);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- /*
- * Checks that the sam account name without a possible "$"
- * matches as prefix with the DNS hostname in the workstation
- * info structure.
- */
- prefix1 = talloc_strndup(mem_ctx, sam_account_name,
- strcspn(sam_account_name, "$"));
- NT_STATUS_HAVE_NO_MEMORY(prefix1);
- if (r->in.query->workstation_info->dns_hostname != NULL) {
- prefix2 = talloc_strndup(mem_ctx,
- r->in.query->workstation_info->dns_hostname,
- strcspn(r->in.query->workstation_info->dns_hostname, "."));
- NT_STATUS_HAVE_NO_MEMORY(prefix2);
-
- if (strcasecmp(prefix1, prefix2) != 0) {
- update_dns_hostname = false;
- }
- } else {
+ if (r->in.query->workstation_info->dns_hostname == NULL) {
update_dns_hostname = false;
}
/*
* Updates the DNS hostname when the client wishes that the
* server should handle this for him
- * ("NETR_WS_FLAG_HANDLES_SPN_UPDATE" not set). And this is
- * obviously only checked when we do already have a
- * "dNSHostName".
+ * ("NETR_WS_FLAG_HANDLES_SPN_UPDATE" not set).
* See MS-NRPC section 3.5.4.3.9
*/
- if ((old_dns_hostname != NULL) &&
- (r->in.query->workstation_info->workstation_flags
+ if ((r->in.query->workstation_info->workstation_flags
& NETR_WS_FLAG_HANDLES_SPN_UPDATE) != 0) {
update_dns_hostname = false;
}
os_version->BuildNumber);
NT_STATUS_HAVE_NO_MEMORY(os_version_str);
- ret = ldb_msg_add_string(new_msg,
- "operatingSystemServicePack",
- os_version->CSDVersion);
+ if (strlen(os_version->CSDVersion) != 0) {
+ ret = ldb_msg_add_string(new_msg,
+ "operatingSystemServicePack",
+ os_version->CSDVersion);
+ } else {
+ ret = samdb_msg_add_delete(sam_ctx, mem_ctx, new_msg,
+ "operatingSystemServicePack");
+ }
if (ret != LDB_SUCCESS) {
return NT_STATUS_NO_MEMORY;
}
}
}
- if (dsdb_replace(sam_ctx, new_msg, 0) != LDB_SUCCESS) {
+ if (dsdb_replace(sam_ctx, new_msg, DSDB_FLAG_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE) != LDB_SUCCESS) {
DEBUG(3,("Impossible to update samdb: %s\n",
ldb_errstring(sam_ctx)));
}
ZERO_STRUCTP(domain_info);
- /* Informations about the local and trusted domains */
+ /* Information about the local and trusted domains */
status = fill_our_one_domain_info(mem_ctx,
our_tdo,
struct dom_sid *user_sid,
struct ldb_dn *obj_dn)
{
- const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL };
+ const char *rodc_attrs[] = { "msDS-NeverRevealGroup",
+ "msDS-RevealOnDemandGroup",
+ "userAccountControl",
+ NULL };
const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
struct ldb_dn *rodc_dn;
int ret;
struct ldb_result *rodc_res = NULL, *obj_res = NULL;
- const struct dom_sid *additional_sids[] = { NULL, NULL };
WERROR werr;
- struct dom_sid *object_sid;
- const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids;
rodc_dn = ldb_dn_new_fmt(mem_ctx, sam_ctx, "<SID=%s>",
dom_sid_string(mem_ctx, user_sid));
if (!ldb_dn_validate(rodc_dn)) goto denied;
- /* do the two searches we need */
+ /*
+ * do the two searches we need
+ * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID list
+ * out of the extended DNs
+ */
ret = dsdb_search_dn(sam_ctx, mem_ctx, &rodc_res, rodc_dn, rodc_attrs,
DSDB_SEARCH_SHOW_EXTENDED_DN);
if (ret != LDB_SUCCESS || rodc_res->count != 1) goto denied;
ret = dsdb_search_dn(sam_ctx, mem_ctx, &obj_res, obj_dn, obj_attrs, 0);
if (ret != LDB_SUCCESS || obj_res->count != 1) goto denied;
- object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid");
+ werr = samdb_confirm_rodc_allowed_to_repl_to(sam_ctx,
+ user_sid,
+ rodc_res->msgs[0],
+ obj_res->msgs[0]);
- additional_sids[0] = object_sid;
-
- werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0],
- mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids);
- if (!W_ERROR_IS_OK(werr)) {
- goto denied;
- }
-
- werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0],
- mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids);
- if (!W_ERROR_IS_OK(werr)) {
- goto denied;
- }
-
- /*
- * The SID list needs to include itself as well as the tokenGroups.
- *
- * TODO determine if sIDHistory is required for this check
- */
- werr = samdb_result_sid_array_ndr(sam_ctx, obj_res->msgs[0],
- mem_ctx, "tokenGroups", &token_sids,
- additional_sids, 1);
- if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
- goto denied;
- }
-
- if (never_reveal_sids &&
- sid_list_match(token_sids, never_reveal_sids)) {
- goto denied;
- }
-
- if (reveal_sids &&
- sid_list_match(token_sids, reveal_sids)) {
+ if (W_ERROR_IS_OK(werr)) {
goto allowed;
}
-
denied:
return false;
allowed:
return NT_STATUS_INVALID_PARAMETER;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
/* Buffer is meant to be 16-bit aligned */
if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
- netlogon_creds_aes_decrypt(creds, r->in.opaque_buffer, r->in.buffer_len);
+ nt_status = netlogon_creds_aes_decrypt(creds,
+ r->in.opaque_buffer,
+ r->in.buffer_len);
} else {
- netlogon_creds_arcfour_crypt(creds, r->in.opaque_buffer, r->in.buffer_len);
+ nt_status = netlogon_creds_arcfour_crypt(creds,
+ r->in.opaque_buffer,
+ r->in.buffer_len);
+ }
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
}
decrypted_blob.data = r->in.opaque_buffer;
static void dcesrv_netr_DsRGetDCName_base_done(struct tevent_req *subreq);
+/* Returns a nonzero value if multiple bits in 'val' are set. */
+static bool multiple_bits_set(uint32_t val)
+{
+ /*
+ * Subtracting one from an integer has the effect of flipping all the
+ * bits from the least significant bit up to and including the least
+ * significant '1' bit. For example,
+ *
+ * 0b101000 - 1
+ * = 0b100111
+ * ====
+ *
+ * If 'val' is zero, all the bits will be flipped and thus the bitwise
+ * AND of 'val' with 'val - 1' will be zero.
+ *
+ * If the integer is nonzero, the least significant '1' bit will be
+ * ANDed with a '0' bit and so will be reset in the final result, but
+ * all other '1' bits will remain set. In other words, the effect of
+ * this expression is to mask off the least significant bit that is
+ * set. Therefore iff the result of 'val & (val - 1)' is non-zero, 'val'
+ * must contain multiple set bits.
+ */
+ return val & (val - 1);
+}
+
static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName_base_state *state)
{
struct dcesrv_call_state *dce_call = state->dce_call;
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
+ struct imessaging_context *imsg_ctx =
+ dcesrv_imessaging_context(dce_call->conn);
TALLOC_CTX *mem_ctx = state->mem_ctx;
struct netr_DsRGetDCNameEx2 *r = &state->r;
struct ldb_context *sam_ctx;
const char *domain_name = NULL;
const char *pdc_ip;
bool different_domain = true;
+ bool force_remote_lookup = false;
+ uint32_t valid_flags;
+ uint32_t this_dc_valid_flags;
+ int dc_level;
ZERO_STRUCTP(r->out.info);
- sam_ctx = samdb_connect(state,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
/* "server_unc" is ignored by w2k3 */
- if (r->in.flags & ~(DSGETDC_VALID_FLAGS)) {
+ /*
+ * With the following flags:
+ * DS_FORCE_REDISCOVERY (Flag A)
+ * DS_DIRECTORY_SERVICE_REQUIRED (Flag B)
+ * DS_DIRECTORY_SERVICE_PREFERRED (Flag C)
+ * DS_GC_SERVER_REQUIRED (Flag D)
+ * DS_PDC_REQUIRED (Flag E)
+ * DS_BACKGROUND_ONLY (Flag F)
+ * DS_IP_REQUIRED (Flag G)
+ * DS_KDC_REQUIRED (Flag H)
+ * DS_TIMESERV_REQUIRED (Flag I)
+ * DS_WRITABLE_REQUIRED (Flag J)
+ * DS_GOOD_TIMESERV_PREFERRED (Flag K)
+ * DS_AVOID_SELF (Flag L)
+ * DS_ONLY_LDAP_NEEDED (Flag M)
+ * DS_IS_FLAT_NAME (Flag N)
+ * DS_IS_DNS_NAME (Flag O)
+ * DS_TRY_NEXTCLOSEST_SITE (Flag P)
+ * DS_DIRECTORY_SERVICE_6_REQUIRED (Flag Q)
+ * DS_WEB_SERVICE_REQUIRED (Flag T)
+ * DS_DIRECTORY_SERVICE_8_REQUIRED (Flag U)
+ * DS_DIRECTORY_SERVICE_9_REQUIRED (Flag V)
+ * DS_DIRECTORY_SERVICE_10_REQUIRED (Flag W)
+ * DS_RETURN_DNS_NAME (Flag R)
+ * DS_RETURN_FLAT_NAME (Flag S)
+ *
+ * MS-NRPC 3.5.4.3.1 says:
+ * ...
+ * On receiving this call, the server MUST perform the following Flags
+ * parameter validations:
+ * - Flags D, E, and H MUST NOT be combined with each other.
+ * - Flag N MUST NOT be combined with the O flag.
+ * - Flag R MUST NOT be combined with the S flag.
+ * - Flags B, Q, U, V, and W MUST NOT be combined with each other.
+ * - Flag K MUST NOT be combined with any of the flags: B, C, D, E, or H.
+ * - Flag P MUST NOT be set when the SiteName parameter is provided.
+ * The server MUST return ERROR_INVALID_FLAGS for any of the previously
+ * mentioned conflicting combinations.
+ * ...
+ */
+
+ valid_flags = DSGETDC_VALID_FLAGS;
+
+ if (r->in.flags & ~valid_flags) {
+ /*
+ * TODO: add tests to prove this (maybe based on the
+ * msDS-Behavior-Version levels of dc, domain and/or forest
+ */
return WERR_INVALID_FLAGS;
}
- if (r->in.flags & DS_GC_SERVER_REQUIRED &&
- r->in.flags & DS_PDC_REQUIRED &&
- r->in.flags & DS_KDC_REQUIRED) {
+ /* Flags D, E, and H MUST NOT be combined with each other. */
+#define _DEH (DS_GC_SERVER_REQUIRED|DS_PDC_REQUIRED|DS_KDC_REQUIRED)
+ if (multiple_bits_set(r->in.flags & _DEH)) {
return WERR_INVALID_FLAGS;
}
+
+ /* Flag N MUST NOT be combined with the O flag. */
if (r->in.flags & DS_IS_FLAT_NAME &&
r->in.flags & DS_IS_DNS_NAME) {
return WERR_INVALID_FLAGS;
}
+
+ /* Flag R MUST NOT be combined with the S flag. */
if (r->in.flags & DS_RETURN_DNS_NAME &&
r->in.flags & DS_RETURN_FLAT_NAME) {
return WERR_INVALID_FLAGS;
}
- if (r->in.flags & DS_DIRECTORY_SERVICE_REQUIRED &&
- r->in.flags & DS_DIRECTORY_SERVICE_6_REQUIRED) {
+
+ /* Flags B, Q, U, V, and W MUST NOT be combined with each other */
+#define _BQUVW ( \
+ DS_DIRECTORY_SERVICE_REQUIRED | \
+ DS_DIRECTORY_SERVICE_6_REQUIRED | \
+ DS_DIRECTORY_SERVICE_8_REQUIRED | \
+ DS_DIRECTORY_SERVICE_9_REQUIRED | \
+ DS_DIRECTORY_SERVICE_10_REQUIRED | \
+0)
+ if (multiple_bits_set(r->in.flags & _BQUVW)) {
return WERR_INVALID_FLAGS;
}
+ /*
+ * Flag K MUST NOT be combined with any of the flags:
+ * B, C, D, E, or H.
+ */
if (r->in.flags & DS_GOOD_TIMESERV_PREFERRED &&
r->in.flags &
(DS_DIRECTORY_SERVICE_REQUIRED |
return WERR_INVALID_FLAGS;
}
+ /* Flag P MUST NOT be set when the SiteName parameter is provided. */
if (r->in.flags & DS_TRY_NEXTCLOSEST_SITE &&
r->in.site_name) {
return WERR_INVALID_FLAGS;
different_domain = false;
}
+ if (!different_domain) {
+ dc_level = dsdb_dc_functional_level(sam_ctx);
+
+ /*
+ * Do not return a local response if we do not support the
+ * functional level or feature (eg web services)
+ */
+ this_dc_valid_flags = valid_flags;
+
+ /* Samba does not implement this */
+ this_dc_valid_flags &= ~DS_WEB_SERVICE_REQUIRED;
+
+ if (dc_level < DS_DOMAIN_FUNCTION_2012) {
+ this_dc_valid_flags &= ~DS_DIRECTORY_SERVICE_8_REQUIRED;
+ }
+ if (dc_level < DS_DOMAIN_FUNCTION_2012_R2) {
+ this_dc_valid_flags &= ~DS_DIRECTORY_SERVICE_9_REQUIRED;
+ }
+ if (dc_level < DS_DOMAIN_FUNCTION_2016) {
+ this_dc_valid_flags &= ~DS_DIRECTORY_SERVICE_10_REQUIRED;
+ }
+ if (r->in.flags & ~this_dc_valid_flags) {
+ DBG_INFO("Forcing remote lookup to find another DC "
+ "in this domain %s with more features, "
+ "as this Samba DC is Functional level %d but flags are 0x08%x\n",
+ r->in.domain_name, dc_level, (unsigned int)r->in.flags);
+ force_remote_lookup = true;
+ }
+ }
+
/* Proof server site parameter "site_name" if it was specified */
server_site_name = samdb_server_site_name(sam_ctx, state);
W_ERROR_HAVE_NO_MEMORY(server_site_name);
- if (different_domain || (r->in.site_name != NULL &&
- (strcasecmp_m(r->in.site_name,
- server_site_name) != 0))) {
+ if (force_remote_lookup
+ || different_domain
+ || (r->in.site_name != NULL &&
+ (strcasecmp_m(r->in.site_name,
+ server_site_name) != 0))) {
struct dcerpc_binding_handle *irpc_handle = NULL;
struct tevent_req *subreq = NULL;
false);
irpc_handle = irpc_binding_handle_by_name(state,
- dce_call->msg_ctx,
+ imsg_ctx,
"winbind_server",
&ndr_table_winbind);
if (irpc_handle == NULL) {
static WERROR dcesrv_netr_DsRAddressToSitenamesExW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsRAddressToSitenamesExW *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct ldb_context *sam_ctx;
struct netr_DsRAddressToSitenamesExWCtr *ctr;
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
sa_family_t sin_family;
struct sockaddr_in *addr;
#ifdef HAVE_IPV6
const char *res;
uint32_t i;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
static WERROR dcesrv_netr_DsrGetDcSiteCoverageW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsrGetDcSiteCoverageW *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct ldb_context *sam_ctx;
struct DcSitesCtr *ctr;
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
return WERR_INVALID_FLAGS;
}
- system_dn = samdb_search_dn(sam_ctx, mem_ctx,
- ldb_get_default_basedn(sam_ctx),
- "(&(objectClass=container)(cn=System))");
- if (!system_dn) {
- return WERR_GEN_FAILURE;
+ system_dn = samdb_system_container_dn(sam_ctx, mem_ctx);
+ if (system_dn == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
}
ret = gendb_search(sam_ctx, mem_ctx, system_dn,
TALLOC_CTX *mem_ctx,
struct netr_DsrEnumerateDomainTrusts *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct netr_DomainTrustList *trusts;
struct ldb_context *sam_ctx;
int ret;
trusts->count = 0;
r->out.trusts = trusts;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_GEN_FAILURE;
}
TALLOC_CTX *mem_ctx,
struct netr_DsRGetForestTrustInformation *r)
{
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
struct auth_session_info *session_info =
dcesrv_call_session_info(dce_call);
+ struct imessaging_context *imsg_ctx =
+ dcesrv_imessaging_context(dce_call->conn);
enum security_user_level security_level;
struct ldb_context *sam_ctx = NULL;
struct dcesrv_netr_DsRGetForestTrustInformation_state *state = NULL;
return WERR_INVALID_FLAGS;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_GEN_FAILURE;
}
state->r = r;
irpc_handle = irpc_binding_handle_by_name(state,
- state->dce_call->msg_ctx,
+ imsg_ctx,
"winbind_server",
&ndr_table_winbind);
if (irpc_handle == NULL) {
TALLOC_CTX *mem_ctx,
struct netr_GetForestTrustInformation *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
struct netlogon_creds_CredentialState *creds = NULL;
struct ldb_context *sam_ctx = NULL;
struct ldb_dn *domain_dn = NULL;
return NT_STATUS_NOT_IMPLEMENTED;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
return NT_STATUS_INVALID_PARAMETER;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- system_session(lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
default:
nt_status = samdb_result_passwords_no_lockout(mem_ctx, lp_ctx,
res[0],
- NULL, &curNtHash);
+ &curNtHash);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
if (curNtHash != NULL) {
*r->out.new_owf_password = *curNtHash;
- netlogon_creds_des_encrypt(creds, r->out.new_owf_password);
+ nt_status = netlogon_creds_des_encrypt(creds, r->out.new_owf_password);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
}
if (prevNtHash != NULL) {
*r->out.old_owf_password = *prevNtHash;
- netlogon_creds_des_encrypt(creds, r->out.old_owf_password);
+ nt_status = netlogon_creds_des_encrypt(creds, r->out.old_owf_password);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
}
if (trust_info != NULL) {
struct dcerpc_binding_handle *binding_handle;
struct netr_dnsupdate_RODC_state *st;
struct tevent_req *subreq;
+ struct imessaging_context *imsg_ctx =
+ dcesrv_imessaging_context(dce_call->conn);
nt_status = dcesrv_netr_creds_server_step_check(dce_call,
mem_ctx,
st->r2->in.dns_names = r->in.dns_names;
st->r2->out.dns_names = r->out.dns_names;
- binding_handle = irpc_binding_handle_by_name(st, dce_call->msg_ctx,
- "dnsupdate", &ndr_table_irpc);
+ binding_handle = irpc_binding_handle_by_name(st,
+ imsg_ctx,
+ "dnsupdate",
+ &ndr_table_irpc);
if (binding_handle == NULL) {
DEBUG(0,("Failed to get binding_handle for dnsupdate task\n"));
dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM;