/*
take a reference to an existing association group
*/
-static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
- struct dcesrv_context *dce_ctx,
+static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(struct dcesrv_connection *conn,
uint32_t id)
{
+ const struct dcesrv_endpoint *endpoint = conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
struct dcesrv_assoc_group *assoc_group;
- assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
+ assoc_group = dcesrv_assoc_group_find(conn->dce_ctx, id);
if (assoc_group == NULL) {
- DEBUG(2,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
+ DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id);
+ return NULL;
+ }
+ if (assoc_group->transport != transport) {
+ const char *at =
+ derpc_transport_string_by_transport(
+ assoc_group->transport);
+ const char *ct =
+ derpc_transport_string_by_transport(
+ transport);
+
+ DBG_NOTICE("assoc_group 0x%08x (transport %s) "
+ "is not available on transport %s",
+ id, at, ct);
return NULL;
}
- return talloc_reference(mem_ctx, assoc_group);
+
+ return talloc_reference(conn, assoc_group);
}
static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
/*
allocate a new association group
*/
-static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
- struct dcesrv_context *dce_ctx)
+static struct dcesrv_assoc_group *dcesrv_assoc_group_new(struct dcesrv_connection *conn)
{
+ struct dcesrv_context *dce_ctx = conn->dce_ctx;
+ const struct dcesrv_endpoint *endpoint = conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
struct dcesrv_assoc_group *assoc_group;
int id;
- assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
+ assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
if (assoc_group == NULL) {
return NULL;
}
return NULL;
}
+ assoc_group->transport = transport;
assoc_group->id = id;
assoc_group->dce_ctx = dce_ctx;
*/
_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
const char *ep_name,
+ const char *ncacn_np_secondary_endpoint,
const struct dcesrv_interface *iface,
const struct security_descriptor *sd)
{
struct dcesrv_endpoint *ep;
struct dcesrv_if_list *ifl;
struct dcerpc_binding *binding;
+ struct dcerpc_binding *binding2 = NULL;
bool add_ep = false;
NTSTATUS status;
enum dcerpc_transport_t transport;
}
}
+ if (transport == NCACN_NP && ncacn_np_secondary_endpoint != NULL) {
+ enum dcerpc_transport_t transport2;
+
+ status = dcerpc_parse_binding(dce_ctx,
+ ncacn_np_secondary_endpoint,
+ &binding2);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Trouble parsing 2nd binding string '%s'\n",
+ ncacn_np_secondary_endpoint));
+ return status;
+ }
+
+ transport2 = dcerpc_binding_get_transport(binding2);
+ SMB_ASSERT(transport2 == transport);
+ }
+
/* see if the interface is already registered on the endpoint */
if (find_interface_by_binding(dce_ctx, binding, iface)!=NULL) {
DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
}
ZERO_STRUCTP(ep);
ep->ep_description = talloc_move(ep, &binding);
+ ep->ep_2nd_description = talloc_move(ep, &binding2);
add_ep = true;
/* add mgmt interface */
DATA_BLOB *session_key)
{
struct dcesrv_auth *auth = call->auth_state;
-
+ SMB_ASSERT(auth->auth_finished);
return dcesrv_session_info_session_key(auth, session_key);
}
struct dcesrv_auth *auth = call->auth_state;
NTSTATUS status;
+ SMB_ASSERT(auth->auth_finished);
+
if (auth->session_key_fn == NULL) {
return NT_STATUS_NO_USER_SESSION_KEY;
}
p->max_xmit_frag = 5840;
p->max_total_request_size = DCERPC_NCACN_REQUEST_DEFAULT_MAX_SIZE;
+ p->support_hdr_signing = lpcfg_parm_bool(dce_ctx->lp_ctx,
+ NULL,
+ "dcesrv",
+ "header signing",
+ true);
+ p->max_auth_states = lpcfg_parm_ulong(dce_ctx->lp_ctx,
+ NULL,
+ "dcesrv",
+ "max auth states",
+ 2049);
+
auth = dcesrv_auth_create(p);
if (auth == NULL) {
talloc_free(p);
static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call,
const char *reason)
{
+ struct dcesrv_auth *a = NULL;
+
if (call->conn->terminate != NULL) {
return;
}
call->conn->allow_bind = false;
call->conn->allow_alter = false;
- call->conn->allow_auth3 = false;
- call->conn->allow_request = false;
call->conn->default_auth_state->auth_invalid = true;
+ for (a = call->conn->auth_states; a != NULL; a = a->next) {
+ a->auth_invalid = true;
+ }
+
call->terminate_reason = talloc_strdup(call, reason);
if (call->terminate_reason == NULL) {
call->terminate_reason = __location__;
context->allow_connect);
}
-NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call,
+NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_connection_context *context,
const struct dcesrv_interface *iface)
{
- if (dce_call->context == NULL) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
/*
* For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
* has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
*/
- dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_PACKET;
+ context->min_auth_level = DCERPC_AUTH_LEVEL_PACKET;
return NT_STATUS_OK;
}
-NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call,
+NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_connection_context *context,
const struct dcesrv_interface *iface)
{
- if (dce_call->context == NULL) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
return NT_STATUS_OK;
}
-_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call,
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_connection_context *context,
const struct dcesrv_interface *iface)
{
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+ struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = context->conn->endpoint;
enum dcerpc_transport_t transport =
dcerpc_binding_get_transport(endpoint->ep_description);
- struct dcesrv_connection_context *context = dce_call->context;
-
- if (context == NULL) {
- return NT_STATUS_INTERNAL_ERROR;
- }
if (transport == NCALRPC) {
context->allow_connect = true;
return NT_STATUS_OK;
}
-_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call,
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_connection_context *context,
const struct dcesrv_interface *iface)
{
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+ struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = context->conn->endpoint;
enum dcerpc_transport_t transport =
dcerpc_binding_get_transport(endpoint->ep_description);
- struct dcesrv_connection_context *context = dce_call->context;
-
- if (context == NULL) {
- return NT_STATUS_INTERNAL_ERROR;
- }
if (transport == NCALRPC) {
context->allow_connect = true;
uint32_t extra_flags = 0;
uint16_t max_req = 0;
uint16_t max_rep = 0;
- const char *ep_prefix = "";
+ struct dcerpc_binding *ep_2nd_description = NULL;
const char *endpoint = NULL;
struct dcesrv_auth *auth = call->auth_state;
struct dcerpc_ack_ctx *ack_ctx_list = NULL;
*/
if (call->pkt.u.bind.assoc_group_id != 0) {
call->conn->assoc_group = dcesrv_assoc_group_reference(call->conn,
- call->conn->dce_ctx,
call->pkt.u.bind.assoc_group_id);
} else {
- call->conn->assoc_group = dcesrv_assoc_group_new(call->conn,
- call->conn->dce_ctx);
+ call->conn->assoc_group = dcesrv_assoc_group_new(call->conn);
}
/*
if (call->conn->assoc_group == NULL &&
!call->conn->endpoint->use_single_process) {
call->conn->assoc_group
- = dcesrv_assoc_group_new(call->conn,
- call->conn->dce_ctx);
+ = dcesrv_assoc_group_new(call->conn);
}
if (call->conn->assoc_group == NULL) {
return dcesrv_bind_nak(call, 0);
a->result = DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK;
a->reason.negotiate = 0;
if (features & DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING) {
- /* not supported yet */
+ if (call->conn->max_auth_states != 0) {
+ a->reason.negotiate |=
+ DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING;
+ }
}
if (features & DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN) {
a->reason.negotiate |=
DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN;
}
- call->conn->bind_time_features = a->reason.negotiate;
+ call->conn->assoc_group->bind_time_features = a->reason.negotiate;
}
/*
pkt->u.bind_ack.max_recv_frag = call->conn->max_recv_frag;
pkt->u.bind_ack.assoc_group_id = call->conn->assoc_group->id;
+ ep_2nd_description = call->conn->endpoint->ep_2nd_description;
+ if (ep_2nd_description == NULL) {
+ ep_2nd_description = call->conn->endpoint->ep_description;
+ }
+
endpoint = dcerpc_binding_get_string_option(
- call->conn->endpoint->ep_description,
+ ep_2nd_description,
"endpoint");
if (endpoint == NULL) {
endpoint = "";
}
- if (strncasecmp(endpoint, "\\pipe\\", 6) == 0) {
- /*
- * TODO: check if this is really needed
- *
- * Or if we should fix this in our idl files.
- */
- ep_prefix = "\\PIPE\\";
- endpoint += 6;
- }
-
- pkt->u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s",
- ep_prefix,
- endpoint);
- if (pkt->u.bind_ack.secondary_address == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
+ pkt->u.bind_ack.secondary_address = endpoint;
pkt->u.bind_ack.num_results = call->pkt.u.bind.num_contexts;
pkt->u.bind_ack.ctx_list = ack_ctx_list;
pkt->u.bind_ack.auth_info = data_blob_null;
struct tevent_req *subreq = NULL;
NTSTATUS status;
- if (!call->conn->allow_auth3) {
+ if (!auth->auth_started) {
return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
}
context->context_id = ctx->context_id;
context->iface = iface;
context->transfer_syntax = *selected_transfer;
- context->private_data = NULL;
DLIST_ADD(call->conn->contexts, context);
call->context = context;
talloc_set_destructor(context, dcesrv_connection_context_destructor);
*/
call->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
- status = iface->bind(call, iface, if_version);
+ status = iface->bind(context, iface);
call->context = NULL;
if (!NT_STATUS_IS_OK(status)) {
/* we don't want to trigger the iface->unbind() hook */
static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
{
TALLOC_CTX *frame = talloc_stackframe();
- const struct dcesrv_auth *auth = call->auth_state;
- const uint32_t bitmask1 = auth->client_hdr_signing ?
+ const uint32_t bitmask1 = call->conn->client_hdr_signing ?
DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
const struct dcerpc_sec_vt_pcontext pcontext = {
.abstract_syntax = call->context->iface->syntax_id,
struct ndr_pull *pull;
NTSTATUS status;
- if (!call->conn->allow_request) {
+ if (!auth->auth_finished) {
return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
}
NTSTATUS status;
struct dcesrv_call_state *call;
struct dcesrv_call_state *existing = NULL;
+ size_t num_auth_ctx = 0;
+ enum dcerpc_AuthType auth_type = 0;
+ enum dcerpc_AuthLevel auth_level = 0;
+ uint32_t auth_context_id = 0;
call = talloc_zero(dce_conn, struct dcesrv_call_state);
if (!call) {
talloc_steal(call, blob.data);
call->pkt = *pkt;
- call->auth_state = dce_conn->default_auth_state;
+ if (dce_conn->max_auth_states == 0) {
+ call->auth_state = dce_conn->default_auth_state;
+ } else if (call->pkt.auth_length == 0) {
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
+ dce_conn->default_auth_level_connect != NULL)
+ {
+ call->auth_state = dce_conn->default_auth_level_connect;
+ } else {
+ call->auth_state = dce_conn->default_auth_state;
+ }
+ }
+
+ if (call->auth_state == NULL) {
+ struct dcesrv_auth *a = NULL;
+
+ auth_type = dcerpc_get_auth_type(&blob);
+ auth_level = dcerpc_get_auth_level(&blob);
+ auth_context_id = dcerpc_get_auth_context_id(&blob);
+
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ dce_conn->default_auth_level_connect = NULL;
+ if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
+ dce_conn->got_explicit_auth_level_connect = true;
+ }
+ }
+
+ for (a = dce_conn->auth_states; a != NULL; a = a->next) {
+ num_auth_ctx++;
+
+ if (a->auth_type != auth_type) {
+ continue;
+ }
+ if (a->auth_finished && a->auth_level != auth_level) {
+ continue;
+ }
+ if (a->auth_context_id != auth_context_id) {
+ continue;
+ }
+
+ DLIST_PROMOTE(dce_conn->auth_states, a);
+ call->auth_state = a;
+ break;
+ }
+ }
+
+ if (call->auth_state == NULL) {
+ struct dcesrv_auth *a = NULL;
+
+ if (num_auth_ctx >= dce_conn->max_auth_states) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ a = dcesrv_auth_create(dce_conn);
+ if (a == NULL) {
+ talloc_free(call);
+ return NT_STATUS_NO_MEMORY;
+ }
+ DLIST_ADD(dce_conn->auth_states, a);
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ /*
+ * This can never be valid.
+ */
+ a->auth_invalid = true;
+ }
+ call->auth_state = a;
+ }
talloc_set_destructor(call, dcesrv_call_dequeue);
/* we have to check the signing here, before combining the
pdus */
if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
- if (!call->conn->allow_request) {
+ dcesrv_default_auth_state_prepare_request(call);
+
+ if (call->auth_state->auth_started &&
+ !call->auth_state->auth_finished) {
return dcesrv_fault_disconnect(call,
DCERPC_NCA_S_PROTO_ERROR);
}
static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
{
struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
+ struct dcesrv_auth *a = NULL;
struct stream_connection *srv_conn;
srv_conn = talloc_get_type(dce_conn->transport.private_data,
struct stream_connection);
dce_conn->wait_private = NULL;
dce_conn->allow_bind = false;
- dce_conn->allow_auth3 = false;
dce_conn->allow_alter = false;
- dce_conn->allow_request = false;
dce_conn->default_auth_state->auth_invalid = true;
+ for (a = dce_conn->auth_states; a != NULL; a = a->next) {
+ a->auth_invalid = true;
+ }
+
if (dce_conn->pending_call_list == NULL) {
char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
for (iface = e->interface_list; iface; iface = iface->next) {
DEBUGADD(0, ("%s ", iface->iface.name));
}
- DEBUGADD(0, ("failed - %s",
+ DEBUGADD(0, ("failed - %s\n",
nt_errstr(status)));
return status;
}
_PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
{
struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
return auth->session_info->credentials;
}
{
struct dcesrv_auth *auth = dce_call->auth_state;
enum security_user_level level;
+ SMB_ASSERT(auth->auth_finished);
level = security_session_user_level(auth->session_info, NULL);
return level >= SECURITY_USER;
}
_PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
{
struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
return auth->session_info->info->account_name;
}
_PUBLIC_ struct auth_session_info *dcesrv_call_session_info(struct dcesrv_call_state *dce_call)
{
struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
return auth->session_info;
}
{
struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
+
if (auth_type != NULL) {
*auth_type = auth->auth_type;
}