#include "auth/auth_sam_reply.h"
#include "dsdb/samdb/samdb.h"
#include "../lib/util/util_ldb.h"
-#include "../lib/util/memcache.h"
#include "../libcli/auth/schannel.h"
#include "libcli/security/security.h"
#include "param/param.h"
#define DCESRV_INTERFACE_NETLOGON_BIND(call, iface) \
dcesrv_interface_netlogon_bind(call, iface)
+
+/*
+ * This #define allows the netlogon interface to accept invalid
+ * association groups, because association groups are to coordinate
+ * handles, and handles are not used in NETLOGON. This in turn avoids
+ * the need to coordinate these across multiple possible NETLOGON
+ * processes
+ */
+#define DCESRV_INTERFACE_NETLOGON_FLAGS DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED
+
static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_call_state *dce_call,
const struct dcesrv_interface *iface)
{
return dcesrv_interface_bind_reject_connect(dce_call, iface);
}
-static struct memcache *global_challenge_table;
-
struct netlogon_server_pipe_state {
struct netr_Credential client_challenge;
struct netr_Credential server_challenge;
{
struct netlogon_server_pipe_state *pipe_state =
talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
- DATA_BLOB key, val;
+ NTSTATUS ntstatus;
ZERO_STRUCTP(r->out.return_credentials);
- if (global_challenge_table == NULL) {
- /*
- * We maintain a global challenge table
- * with a fixed size (8k)
- *
- * This is required for the strange clients
- * which use different connections for
- * netr_ServerReqChallenge() and netr_ServerAuthenticate3()
- *
- */
- global_challenge_table = memcache_init(talloc_autofree_context(),
- 8192);
- if (global_challenge_table == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- }
-
- /* destroyed on pipe shutdown */
-
if (pipe_state) {
talloc_free(pipe_state);
dce_call->context->private_data = NULL;
dce_call->context->private_data = pipe_state;
- key = data_blob_string_const(r->in.computer_name);
- val = data_blob_const(pipe_state, sizeof(*pipe_state));
-
- memcache_add(global_challenge_table, SINGLETON_CACHE, key, val);
+ 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)) {
+ return ntstatus;
+ }
return NT_STATUS_OK;
}
{
struct netlogon_server_pipe_state *pipe_state =
talloc_get_type(dce_call->context->private_data, struct netlogon_server_pipe_state);
- DATA_BLOB challenge_key;
bool challenge_valid = false;
struct netlogon_server_pipe_state challenge;
struct netlogon_creds_CredentialState *creds;
ZERO_STRUCTP(r->out.return_credentials);
*r->out.rid = 0;
- challenge_key = data_blob_string_const(r->in.computer_name);
if (pipe_state != NULL) {
dce_call->context->private_data = NULL;
* netr_ServerAuthenticate3() on the same dcerpc connection.
*/
challenge = *pipe_state;
- TALLOC_FREE(pipe_state);
+
challenge_valid = true;
+
} else {
- DATA_BLOB val;
- bool ok;
+ NTSTATUS ntstatus;
/*
* Fallback and try to get the challenge from
*
* If too many clients are using this code path,
* they may destroy their cache entries as the
- * global_challenge_table memcache has a fixed size.
+ * TDB has a fixed size limited via a lossy hash
+ *
+ * The TDB used is the schannel store, which is
+ * initialised at startup.
+ *
+ * NOTE: The challenge is deleted from the DB as soon as it is
+ * fetched, to prevent reuse.
*
- * Note: this handles global_challenge_table == NULL fine
*/
- ok = memcache_lookup(global_challenge_table, SINGLETON_CACHE,
- challenge_key, &val);
- if (ok && val.length == sizeof(challenge)) {
- memcpy(&challenge, val.data, sizeof(challenge));
- challenge_valid = true;
- } else {
+
+ ntstatus = schannel_get_challenge(dce_call->conn->dce_ctx->lp_ctx,
+ &challenge.client_challenge,
+ &challenge.server_challenge,
+ r->in.computer_name);
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
ZERO_STRUCT(challenge);
+ } else {
+ challenge_valid = true;
}
}
}
/*
- * At this point we can cleanup the cache entry,
- * if we fail the client needs to call netr_ServerReqChallenge
- * again.
+ * 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 global_challenge_table == NULL
- * and also a non existing record just fine.
+ * 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.
*/
- memcache_delete(global_challenge_table,
- SINGLETON_CACHE, challenge_key);
+ schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx,
+ r->in.computer_name);
/*
* According to Microsoft (see bugid #6099)
This version of the function allows other wrappers to say 'do not check the credentials'
- We can't do the traditional 'wrapping' format completly, as this function must only run under schannel
+ We can't do the traditional 'wrapping' format completely, as this
+ function must only run under schannel
*/
static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_LogonSamLogonEx *r, struct netlogon_creds_CredentialState *creds)
{
struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
const char *workgroup = lpcfg_workgroup(lp_ctx);
- struct auth4_context *auth_context;
- struct auth_usersupplied_info *user_info;
- struct auth_user_info_dc *user_info_dc;
+ struct auth4_context *auth_context = NULL;
+ struct auth_usersupplied_info *user_info = NULL;
+ struct auth_user_info_dc *user_info_dc = NULL;
NTSTATUS nt_status;
- struct netr_SamBaseInfo *sam;
- struct netr_SamInfo2 *sam2;
- struct netr_SamInfo3 *sam3;
- struct netr_SamInfo6 *sam6;
+ struct netr_SamInfo2 *sam2 = NULL;
+ struct netr_SamInfo3 *sam3 = NULL;
+ struct netr_SamInfo6 *sam6 = NULL;
*r->out.authoritative = 1;
switch (r->in.validation_level) {
case 2:
- nt_status = auth_convert_user_info_dc_sambaseinfo(mem_ctx, user_info_dc, &sam);
+ nt_status = auth_convert_user_info_dc_saminfo2(mem_ctx,
+ user_info_dc,
+ &sam2);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam2 = talloc_zero(mem_ctx, struct netr_SamInfo2);
- NT_STATUS_HAVE_NO_MEMORY(sam2);
- sam2->base = *sam;
-
- /* And put into the talloc tree */
- talloc_steal(sam2, sam);
r->out.validation->sam2 = sam2;
-
- sam = &sam2->base;
break;
case 3:
nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx,
- user_info_dc,
- &sam3);
+ user_info_dc,
+ &sam3);
NT_STATUS_NOT_OK_RETURN(nt_status);
r->out.validation->sam3 = sam3;
-
- sam = &sam3->base;
break;
case 6:
return NT_STATUS_INVALID_PARAMETER;
}
- nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx,
- user_info_dc,
- &sam3);
+ nt_status = auth_convert_user_info_dc_saminfo6(mem_ctx,
+ user_info_dc,
+ &sam6);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam6 = talloc_zero(mem_ctx, struct netr_SamInfo6);
- NT_STATUS_HAVE_NO_MEMORY(sam6);
- sam6->base = sam3->base;
- sam = &sam6->base;
- sam6->sidcount = sam3->sidcount;
- sam6->sids = sam3->sids;
-
- sam6->dns_domainname.string = lpcfg_dnsdomain(dce_call->conn->dce_ctx->lp_ctx);
- sam6->principal_name.string = talloc_asprintf(
- mem_ctx, "%s@%s", sam->account_name.string,
- sam6->dns_domainname.string);
- NT_STATUS_HAVE_NO_MEMORY(sam6->principal_name.string);
- /* And put into the talloc tree */
- talloc_steal(sam6, sam3);
-
r->out.validation->sam6 = sam6;
break;
size_t len = strlen(r->in.domainname);
if (dot || len > 15) {
- return WERR_DCNOTFOUND;
+ return WERR_NERR_DCNOTFOUND;
}
/*
info1 = talloc_zero(state->mem_ctx,
struct netr_NETLOGON_INFO_1);
if (info1 == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->r.out.query->info1 = info1;
return WERR_OK;
info3 = talloc_zero(state->mem_ctx,
struct netr_NETLOGON_INFO_3);
if (info3 == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->r.out.query->info3 = info3;
return WERR_OK;
state->r.in.data,
state->r.out.query);
if (subreq == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
tevent_req_set_callback(subreq,
state = talloc_zero(mem_ctx, struct dcesrv_netr_LogonControl_base_state);
if (state == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->dce_call = dce_call;
state = talloc_zero(mem_ctx, struct dcesrv_netr_LogonControl_base_state);
if (state == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->dce_call = dce_call;
state = talloc_zero(mem_ctx, struct dcesrv_netr_LogonControl_base_state);
if (state == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->dce_call = dce_call;
ldb_get_default_basedn(sam_ctx),
"(&(objectClass=container)(cn=System))");
if (!system_dn) {
- return WERR_GENERAL_FAILURE;
+ return WERR_GEN_FAILURE;
}
ret = gendb_search(sam_ctx, mem_ctx, system_dn,
sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
dce_call->conn->auth_state.session_info, 0);
if (sam_ctx == NULL) {
- return WERR_GENERAL_FAILURE;
+ return WERR_GEN_FAILURE;
}
if ((r->in.trust_flags & NETR_TRUST_FLAG_INBOUND) ||
ret = gendb_search_dn(sam_ctx, mem_ctx, NULL,
&dom_res, dom_attrs);
if (ret != 1) {
- return WERR_GENERAL_FAILURE;
+ return WERR_GEN_FAILURE;
}
trusts->count = n + 1;
sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, lp_ctx,
dce_call->conn->auth_state.session_info, 0);
if (sam_ctx == NULL) {
- return WERR_GENERAL_FAILURE;
+ return WERR_GEN_FAILURE;
}
domain_dn = ldb_get_default_basedn(sam_ctx);
if (domain_dn == NULL) {
- return WERR_GENERAL_FAILURE;
+ return WERR_GEN_FAILURE;
}
forest_dn = ldb_get_root_basedn(sam_ctx);
if (forest_dn == NULL) {
- return WERR_GENERAL_FAILURE;
+ return WERR_GEN_FAILURE;
}
cmp = ldb_dn_compare(domain_dn, forest_dn);
state = talloc_zero(mem_ctx,
struct dcesrv_netr_DsRGetForestTrustInformation_state);
if (state == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->dce_call = dce_call;
state->mem_ctx = mem_ctx;
r->in.flags,
r->out.forest_trust_info);
if (subreq == NULL) {
- return WERR_NOMEM;
+ return WERR_NOT_ENOUGH_MEMORY;
}
state->dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
tevent_req_set_callback(subreq,