/*
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 */
_PUBLIC_ NTSTATUS dcesrv_auth_session_key(struct dcesrv_call_state *call,
DATA_BLOB *session_key)
{
- struct dcesrv_auth *auth = &call->conn->auth_state;
-
+ struct dcesrv_auth *auth = call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
return dcesrv_session_info_session_key(auth, session_key);
}
_PUBLIC_ NTSTATUS dcesrv_transport_session_key(struct dcesrv_call_state *call,
DATA_BLOB *session_key)
{
- struct dcesrv_auth *auth = &call->conn->auth_state;
+ 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;
}
return NT_STATUS_OK;
}
+static struct dcesrv_auth *dcesrv_auth_create(struct dcesrv_connection *conn)
+{
+ const struct dcesrv_endpoint *ep = conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(ep->ep_description);
+ struct dcesrv_auth *auth = NULL;
+
+ auth = talloc_zero(conn, struct dcesrv_auth);
+ if (auth == NULL) {
+ return NULL;
+ }
+
+ switch (transport) {
+ case NCACN_NP:
+ auth->session_key_fn = dcesrv_remote_session_key;
+ break;
+ case NCALRPC:
+ case NCACN_UNIX_STREAM:
+ auth->session_key_fn = dcesrv_local_fixed_session_key;
+ break;
+ default:
+ /*
+ * All other's get a NULL pointer, which
+ * results in NT_STATUS_NO_USER_SESSION_KEY
+ */
+ break;
+ }
+
+ return auth;
+}
+
/*
connect to a dcerpc endpoint
*/
uint32_t state_flags,
struct dcesrv_connection **_p)
{
- enum dcerpc_transport_t transport =
- dcerpc_binding_get_transport(ep->ep_description);
+ struct dcesrv_auth *auth = NULL;
struct dcesrv_connection *p;
if (!session_info) {
p = talloc_zero(mem_ctx, struct dcesrv_connection);
NT_STATUS_HAVE_NO_MEMORY(p);
- if (!talloc_reference(p, session_info)) {
- talloc_free(p);
- return NT_STATUS_NO_MEMORY;
- }
-
p->dce_ctx = dce_ctx;
p->endpoint = ep;
p->packet_log_dir = lpcfg_lock_directory(dce_ctx->lp_ctx);
p->max_xmit_frag = 5840;
p->max_total_request_size = DCERPC_NCACN_REQUEST_DEFAULT_MAX_SIZE;
- p->auth_state.session_info = session_info;
- switch (transport) {
- case NCACN_NP:
- p->auth_state.session_key_fn = dcesrv_remote_session_key;
- break;
- case NCALRPC:
- case NCACN_UNIX_STREAM:
- p->auth_state.session_key_fn = dcesrv_local_fixed_session_key;
- break;
- default:
- /*
- * All other's get a NULL pointer, which
- * results in NT_STATUS_NO_USER_SESSION_KEY
- */
- break;
+ p->support_hdr_signing = lpcfg_parm_bool(dce_ctx->lp_ctx,
+ NULL,
+ "dcesrv",
+ "header signing",
+ true);
+
+ auth = dcesrv_auth_create(p);
+ if (auth == NULL) {
+ talloc_free(p);
+ return NT_STATUS_NO_MEMORY;
}
+ auth->session_info = talloc_reference(auth, session_info);
+ if (auth->session_info == NULL) {
+ talloc_free(p);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p->default_auth_state = auth;
+
/*
* For now we only support NDR32.
*/
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;
call->terminate_reason = talloc_strdup(call, reason);
if (call->terminate_reason == NULL) {
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->conn->auth_state;
+ struct dcesrv_auth *auth = call->auth_state;
struct dcerpc_ack_ctx *ack_ctx_list = NULL;
struct dcerpc_ack_ctx *ack_features = NULL;
struct tevent_req *subreq = 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);
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;
static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
{
struct dcesrv_connection *conn = call->conn;
- struct dcesrv_auth *auth = &call->conn->auth_state;
+ struct dcesrv_auth *auth = call->auth_state;
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);
}
tevent_req_callback_data(subreq,
struct dcesrv_call_state);
struct dcesrv_connection *conn = call->conn;
- struct dcesrv_auth *auth = &call->conn->auth_state;
+ struct dcesrv_auth *auth = call->auth_state;
NTSTATUS status;
status = gensec_update_recv(subreq, call,
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 */
bool auth_ok = false;
struct ncacn_packet *pkt = &call->ack_pkt;
uint32_t extra_flags = 0;
- struct dcesrv_auth *auth = &call->conn->auth_state;
+ struct dcesrv_auth *auth = call->auth_state;
struct dcerpc_ack_ctx *ack_ctx_list = NULL;
struct tevent_req *subreq = NULL;
size_t i;
static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
{
TALLOC_CTX *frame = talloc_stackframe();
- const struct dcesrv_auth *auth = &call->conn->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,
static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
{
const struct dcesrv_endpoint *endpoint = call->conn->endpoint;
- struct dcesrv_auth *auth = &call->conn->auth_state;
+ struct dcesrv_auth *auth = call->auth_state;
enum dcerpc_transport_t transport =
dcerpc_binding_get_transport(endpoint->ep_description);
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);
}
talloc_steal(call, blob.data);
call->pkt = *pkt;
+ call->auth_state = dce_conn->default_auth_state;
+
talloc_set_destructor(call, dcesrv_call_dequeue);
if (call->conn->allow_bind) {
/* we have to check the signing here, before combining the
pdus */
if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
- if (!call->conn->allow_request) {
+ if (!call->auth_state->auth_finished) {
return dcesrv_fault_disconnect(call,
DCERPC_NCA_S_PROTO_ERROR);
}
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;
if (dce_conn->pending_call_list == NULL) {
char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
*/
_PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
{
- struct dcesrv_auth *auth = &dce_call->conn->auth_state;
+ struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
return auth->session_info->credentials;
}
*/
_PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
{
- struct dcesrv_auth *auth = &dce_call->conn->auth_state;
+ 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->conn->auth_state;
+ 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->conn->auth_state;
+ struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
return auth->session_info;
}
enum dcerpc_AuthType *auth_type,
enum dcerpc_AuthLevel *auth_level)
{
- struct dcesrv_auth *auth = &dce_call->conn->auth_state;
+ struct dcesrv_auth *auth = dce_call->auth_state;
+
+ SMB_ASSERT(auth->auth_finished);
if (auth_type != NULL) {
*auth_type = auth->auth_type;