X-Git-Url: http://git.samba.org/?p=samba.git;a=blobdiff_plain;f=source4%2Frpc_server%2Fdcerpc_server.c;h=7ceaf03c673eaa3ad1e3c14e9eba1f771afa4f20;hp=550b18d060b21790846a4471a6a8c2b8aee28224;hb=57edc9a0d5fe092252b102c6bb34d94e5d5c13c1;hpb=133130d2638ce5655d95c5efc14e6b6ed8304159 diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 550b18d060b..7ceaf03c673 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -41,8 +41,7 @@ #include "librpc/rpc/rpc_common.h" #include "lib/util/samba_modules.h" #include "librpc/gen_ndr/ndr_dcerpc.h" - -extern const struct dcesrv_interface dcesrv_mgmt_interface; +#include "../lib/util/tevent_ntstatus.h" static NTSTATUS dcesrv_negotiate_contexts(struct dcesrv_call_state *call, const struct dcerpc_bind *b, @@ -192,15 +191,21 @@ static bool interface_match(const struct dcesrv_interface *if1, } /* - find the interface operations on an endpoint + find the interface operations on any endpoint with this binding */ -static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint, - const struct dcesrv_interface *iface) +static const struct dcesrv_interface *find_interface_by_binding(struct dcesrv_context *dce_ctx, + struct dcerpc_binding *binding, + const struct dcesrv_interface *iface) { - struct dcesrv_if_list *ifl; - for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) { - if (interface_match(&(ifl->iface), iface)) { - return &(ifl->iface); + struct dcesrv_endpoint *ep; + for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) { + if (endpoints_match(ep->ep_description, binding)) { + struct dcesrv_if_list *ifl; + for (ifl=ep->interface_list; ifl; ifl=ifl->next) { + if (interface_match(&(ifl->iface), iface)) { + return &(ifl->iface); + } + } } } return NULL; @@ -219,8 +224,8 @@ static bool interface_match_by_uuid(const struct dcesrv_interface *iface, /* find the interface operations on an endpoint by uuid */ -static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint, - const struct GUID *uuid, uint32_t if_version) +const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint, + const struct GUID *uuid, uint32_t if_version) { struct dcesrv_if_list *ifl; for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) { @@ -234,7 +239,7 @@ static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv /* find the earlier parts of a fragmented call awaiting reassembily */ -static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id) +static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint32_t call_id) { struct dcesrv_call_state *c; for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) { @@ -247,6 +252,15 @@ static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_conne /* register an interface on an endpoint + + An endpoint is one unix domain socket (for ncalrpc), one TCP port + (for ncacn_ip_tcp) or one (forwarded) named pipe (for ncacn_np). + + Each endpoint can have many interfaces such as netlogon, lsa or + samr. Some have essentially the full set. + + This is driven from the set of interfaces listed in each IDL file + via the PIDL generated *__op_init_server() functions. */ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, const char *ep_name, @@ -258,7 +272,24 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, struct dcerpc_binding *binding; bool add_ep = false; NTSTATUS status; - + enum dcerpc_transport_t transport; + char *ep_string = NULL; + bool use_single_process = true; + const char *ep_process_string; + + /* + * If we are not using handles, there is no need for force + * this service into using a single process. + * + * However, due to the way we listen for RPC packets, we can + * only do this if we have a single service per pipe or TCP + * port, so we still force a single combined process for + * ncalrpc. + */ + if (iface->flags & DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED) { + use_single_process = false; + } + status = dcerpc_parse_binding(dce_ctx, ep_name, &binding); if (NT_STATUS_IS_ERR(status)) { @@ -266,9 +297,78 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, return status; } + transport = dcerpc_binding_get_transport(binding); + if (transport == NCACN_IP_TCP) { + int port; + char port_str[6]; + + /* + * First check if there is already a port specified, eg + * for epmapper on ncacn_ip_tcp:[135] + */ + const char *endpoint + = dcerpc_binding_get_string_option(binding, + "endpoint"); + if (endpoint == NULL) { + port = lpcfg_parm_int(dce_ctx->lp_ctx, NULL, + "rpc server port", iface->name, 0); + + /* + * For RPC services that are not set to use a single + * process, we do not default to using the 'rpc server + * port' because that would cause a double-bind on + * that port. + */ + if (port == 0 && !use_single_process) { + port = lpcfg_rpc_server_port(dce_ctx->lp_ctx); + } + if (port != 0) { + snprintf(port_str, sizeof(port_str), "%u", port); + status = dcerpc_binding_set_string_option(binding, + "endpoint", + port_str); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + } + } + + /* 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", + iface->name, ep_name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + /* check if this endpoint exists */ - if ((ep=find_endpoint(dce_ctx, binding))==NULL) { + ep = find_endpoint(dce_ctx, binding); + + if (ep != NULL) { + /* + * We want a new port on ncacn_ip_tcp for NETLOGON, so + * it can be multi-process. Other processes can also + * listen on distinct ports, if they have one forced + * in the code above with eg 'rpc server port:drsuapi = 1027' + * + * If we have mulitiple endpoints on port 0, they each + * get an epemeral port (currently by walking up from + * 1024). + * + * Because one endpoint can only have one process + * model, we add a new IP_TCP endpoint for each model. + * + * This works in conjunction with the forced overwrite + * of ep->use_single_process below. + */ + if (ep->use_single_process != use_single_process + && transport == NCACN_IP_TCP) { + add_ep = true; + } + } + + if (ep == NULL || add_ep) { ep = talloc_zero(dce_ctx, struct dcesrv_endpoint); if (!ep) { return NT_STATUS_NO_MEMORY; @@ -283,17 +383,21 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, return NT_STATUS_NO_MEMORY; } - memcpy(&(ifl->iface), &dcesrv_mgmt_interface, - sizeof(struct dcesrv_interface)); + ifl->iface = dcesrv_get_mgmt_interface(); DLIST_ADD(ep->interface_list, ifl); } - /* see if the interface is already registered on te endpoint */ - if (find_interface(ep, iface)!=NULL) { - DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n", - iface->name, ep_name)); - return NT_STATUS_OBJECT_NAME_COLLISION; + /* + * By default don't force into a single process, but if any + * interface on this endpoint on this service uses handles + * (most do), then we must force into single process mode + * + * By overwriting this each time a new interface is added to + * this endpoint, we end up with the most restrictive setting. + */ + if (use_single_process) { + ep->use_single_process = true; } /* talloc a new interface list element */ @@ -338,20 +442,74 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, DLIST_ADD(dce_ctx->endpoint_list, ep); } - DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n", - iface->name, ep_name)); + /* Re-get the string as we may have set a port */ + ep_string = dcerpc_binding_string(dce_ctx, ep->ep_description); + + if (use_single_process) { + ep_process_string = "single process required"; + } else { + ep_process_string = "multi process compatible"; + } + + DBG_INFO("dcesrv_interface_register: interface '%s' " + "registered on endpoint '%s' (%s)\n", + iface->name, ep_string, ep_process_string); + TALLOC_FREE(ep_string); return NT_STATUS_OK; } +static NTSTATUS dcesrv_session_info_session_key(struct dcesrv_auth *auth, + DATA_BLOB *session_key) +{ + if (auth->session_info == NULL) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + if (auth->session_info->session_key.length == 0) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + *session_key = auth->session_info->session_key; + return NT_STATUS_OK; +} + +static NTSTATUS dcesrv_remote_session_key(struct dcesrv_auth *auth, + DATA_BLOB *session_key) +{ + if (auth->auth_type != DCERPC_AUTH_TYPE_NONE) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + return dcesrv_session_info_session_key(auth, session_key); +} + +static NTSTATUS dcesrv_local_fixed_session_key(struct dcesrv_auth *auth, + DATA_BLOB *session_key) +{ + return dcerpc_generic_session_key(NULL, session_key); +} + NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p, DATA_BLOB *session_key) { - if (p->auth_state.session_info->session_key.length) { - *session_key = p->auth_state.session_info->session_key; - return NT_STATUS_OK; - } - return NT_STATUS_NO_USER_SESSION_KEY; + struct dcesrv_auth *auth = &p->auth_state; + + return dcesrv_remote_session_key(auth, session_key); +} + +/* + * Fetch the authentication session key if available. + * + * This is the key generated by a gensec authentication. + * + */ +_PUBLIC_ NTSTATUS dcesrv_auth_session_key(struct dcesrv_call_state *call, + DATA_BLOB *session_key) +{ + struct dcesrv_auth *auth = &call->conn->auth_state; + + return dcesrv_session_info_session_key(auth, session_key); } /* @@ -362,7 +520,14 @@ NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p, _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p, DATA_BLOB *session_key) { - NTSTATUS status = p->auth_state.session_key(p, session_key); + struct dcesrv_auth *auth = &p->auth_state; + NTSTATUS status; + + if (auth->session_key_fn == NULL) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + status = auth->session_key_fn(auth, session_key); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -372,10 +537,23 @@ _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p, return NT_STATUS_OK; } +/* + * Fetch the transport session key if available. + * Typically this is the SMB session key + * or a fixed key for local transports. + * + * The key is always truncated to 16 bytes. +*/ +_PUBLIC_ NTSTATUS dcesrv_transport_session_key(struct dcesrv_call_state *call, + DATA_BLOB *session_key) +{ + return dcesrv_fetch_session_key(call->conn, session_key); +} + /* connect to a dcerpc endpoint */ -_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, +static NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, TALLOC_CTX *mem_ctx, const struct dcesrv_endpoint *ep, struct auth_session_info *session_info, @@ -385,6 +563,8 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, uint32_t state_flags, struct dcesrv_connection **_p) { + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(ep->ep_description); struct dcesrv_connection *p; if (!session_info) { @@ -402,8 +582,6 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, p->dce_ctx = dce_ctx; p->endpoint = ep; p->packet_log_dir = lpcfg_lock_directory(dce_ctx->lp_ctx); - p->auth_state.session_info = session_info; - p->auth_state.session_key = dcesrv_generic_session_key; p->event_ctx = event_ctx; p->msg_ctx = msg_ctx; p->server_id = server_id; @@ -413,6 +591,23 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_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; + } + /* * For now we only support NDR32. */ @@ -669,21 +864,113 @@ _PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state * return NT_STATUS_OK; } +struct dcesrv_conn_auth_wait_context { + struct tevent_req *req; + bool done; + NTSTATUS status; +}; + +struct dcesrv_conn_auth_wait_state { + uint8_t dummy; +}; + +static struct tevent_req *dcesrv_conn_auth_wait_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + void *private_data) +{ + struct dcesrv_conn_auth_wait_context *auth_wait = + talloc_get_type_abort(private_data, + struct dcesrv_conn_auth_wait_context); + struct tevent_req *req = NULL; + struct dcesrv_conn_auth_wait_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct dcesrv_conn_auth_wait_state); + if (req == NULL) { + return NULL; + } + auth_wait->req = req; + + tevent_req_defer_callback(req, ev); + + if (!auth_wait->done) { + return req; + } + + if (tevent_req_nterror(req, auth_wait->status)) { + return tevent_req_post(req, ev); + } + + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +static NTSTATUS dcesrv_conn_auth_wait_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +static NTSTATUS dcesrv_conn_auth_wait_setup(struct dcesrv_connection *conn) +{ + struct dcesrv_conn_auth_wait_context *auth_wait = NULL; + + if (conn->wait_send != NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + auth_wait = talloc_zero(conn, struct dcesrv_conn_auth_wait_context); + if (auth_wait == NULL) { + return NT_STATUS_NO_MEMORY; + } + + conn->wait_private = auth_wait; + conn->wait_send = dcesrv_conn_auth_wait_send; + conn->wait_recv = dcesrv_conn_auth_wait_recv; + return NT_STATUS_OK; +} + +static void dcesrv_conn_auth_wait_finished(struct dcesrv_connection *conn, + NTSTATUS status) +{ + struct dcesrv_conn_auth_wait_context *auth_wait = + talloc_get_type_abort(conn->wait_private, + struct dcesrv_conn_auth_wait_context); + + auth_wait->done = true; + auth_wait->status = status; + + if (auth_wait->req == NULL) { + return; + } + + if (tevent_req_nterror(auth_wait->req, status)) { + return; + } + + tevent_req_done(auth_wait->req); +} + +static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call); + +static void dcesrv_bind_done(struct tevent_req *subreq); + /* handle a bind request */ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) { - struct ncacn_packet pkt; - struct data_blob_list_item *rep; + struct dcesrv_connection *conn = call->conn; + struct ncacn_packet *pkt = &call->ack_pkt; NTSTATUS status; uint32_t extra_flags = 0; uint16_t max_req = 0; uint16_t max_rep = 0; const char *ep_prefix = ""; const char *endpoint = NULL; + struct dcesrv_auth *auth = &call->conn->auth_state; struct dcerpc_ack_ctx *ack_ctx_list = NULL; struct dcerpc_ack_ctx *ack_features = NULL; + struct tevent_req *subreq = NULL; size_t i; status = dcerpc_verify_ncacn_packet_header(&call->pkt, @@ -730,6 +1017,33 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) call->conn->assoc_group = dcesrv_assoc_group_new(call->conn, call->conn->dce_ctx); } + + /* + * The NETLOGON server does not use handles and so + * there is no need to support association groups, but + * we need to give back a number regardless. + * + * We have to do this when it is not run as a single process, + * because then it can't see the other valid association + * groups. We handle this genericly for all endpoints not + * running in single process mode. + * + * We know which endpoint we are on even before checking the + * iface UUID, so for simplicity we enforce the same policy + * for all interfaces on the endpoint. + * + * This means that where NETLOGON + * shares an endpoint (such as ncalrpc or of 'lsa over + * netlogon' is set) we will still check association groups. + * + */ + + 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); + } if (call->conn->assoc_group == NULL) { return dcesrv_bind_nak(call, 0); } @@ -795,6 +1109,14 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) /* * Try to negotiate one new presentation context. + * + * Deep in here we locate the iface (by uuid) that the client + * requested, from the list of interfaces on the + * call->conn->endpoint, and call iface->bind() on that iface. + * + * call->conn was set up at the accept() of the socket, and + * call->conn->endpoint has a list of interfaces restricted to + * this port or pipe. */ status = dcesrv_negotiate_contexts(call, &call->pkt.u.bind, ack_ctx_list); if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) { @@ -804,6 +1126,15 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) return status; } + /* + * At this point we still don't know which interface (eg + * netlogon, lsa, drsuapi) the caller requested in this bind! + * The most recently added context is available as the first + * element in the linked list at call->conn->contexts, that is + * call->conn->contexts->iface, but they may not have + * requested one at all! + */ + if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) && (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) { call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED; @@ -814,11 +1145,12 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL; } - /* handle any authentication that is being requested */ + /* + * After finding the interface and setting up the NDR + * transport negotiation etc, handle any authentication that + * is being requested. + */ if (!dcesrv_auth_bind(call)) { - struct dcesrv_auth *auth = &call->conn->auth_state; - - TALLOC_FREE(call->context); if (auth->auth_level == DCERPC_AUTH_LEVEL_NONE) { /* @@ -837,14 +1169,14 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) } /* setup a bind_ack */ - dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); - pkt.auth_length = 0; - pkt.call_id = call->pkt.call_id; - pkt.ptype = DCERPC_PKT_BIND_ACK; - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; - pkt.u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag; - pkt.u.bind_ack.max_recv_frag = call->conn->max_recv_frag; - pkt.u.bind_ack.assoc_group_id = call->conn->assoc_group->id; + dcesrv_init_hdr(pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); + pkt->auth_length = 0; + pkt->call_id = call->pkt.call_id; + pkt->ptype = DCERPC_PKT_BIND_ACK; + pkt->pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; + pkt->u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag; + pkt->u.bind_ack.max_recv_frag = call->conn->max_recv_frag; + pkt->u.bind_ack.assoc_group_id = call->conn->assoc_group->id; endpoint = dcerpc_binding_get_string_option( call->conn->endpoint->ep_description, @@ -863,33 +1195,74 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) endpoint += 6; } - pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s", + pkt->u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s", ep_prefix, endpoint); - if (pkt.u.bind_ack.secondary_address == NULL) { - TALLOC_FREE(call->context); + if (pkt->u.bind_ack.secondary_address == NULL) { return NT_STATUS_NO_MEMORY; } - 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; + 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; - status = dcesrv_auth_bind_ack(call, &pkt); + status = dcesrv_auth_prepare_bind_ack(call, pkt); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(call->context); return dcesrv_bind_nak(call, 0); } + if (auth->auth_finished) { + return dcesrv_auth_reply(call); + } + + subreq = gensec_update_send(call, call->event_ctx, + auth->gensec_security, + call->in_auth_info.credentials); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; + } + tevent_req_set_callback(subreq, dcesrv_bind_done, call); + + return dcesrv_conn_auth_wait_setup(conn); +} + +static void dcesrv_bind_done(struct tevent_req *subreq) +{ + struct dcesrv_call_state *call = + tevent_req_callback_data(subreq, + struct dcesrv_call_state); + struct dcesrv_connection *conn = call->conn; + NTSTATUS status; + + status = gensec_update_recv(subreq, call, + &call->out_auth_info->credentials); + TALLOC_FREE(subreq); + + status = dcesrv_auth_complete(call, status); + if (!NT_STATUS_IS_OK(status)) { + status = dcesrv_bind_nak(call, 0); + dcesrv_conn_auth_wait_finished(conn, status); + return; + } + + status = dcesrv_auth_reply(call); + dcesrv_conn_auth_wait_finished(conn, status); + return; +} + +static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call) +{ + struct ncacn_packet *pkt = &call->ack_pkt; + struct data_blob_list_item *rep = NULL; + NTSTATUS status; + rep = talloc_zero(call, struct data_blob_list_item); if (!rep) { - TALLOC_FREE(call->context); return NT_STATUS_NO_MEMORY; } - status = ncacn_push_auth(&rep->blob, call, &pkt, + status = ncacn_push_auth(&rep->blob, call, pkt, call->out_auth_info); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(call->context); return status; } @@ -908,11 +1281,16 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) } +static void dcesrv_auth3_done(struct tevent_req *subreq); + /* handle a auth3 request */ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call) { + struct dcesrv_connection *conn = call->conn; + struct dcesrv_auth *auth = &call->conn->auth_state; + struct tevent_req *subreq = NULL; NTSTATUS status; if (!call->conn->allow_auth3) { @@ -940,18 +1318,71 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call) } /* handle the auth3 in the auth code */ - if (!dcesrv_auth_auth3(call)) { + if (!dcesrv_auth_prepare_auth3(call)) { + /* + * we don't send a reply to a auth3 request, + * except by a fault. + * + * In anycase we mark the connection as + * invalid. + */ call->conn->auth_state.auth_invalid = true; if (call->fault_code != 0) { return dcesrv_fault_disconnect(call, call->fault_code); } + TALLOC_FREE(call); + return NT_STATUS_OK; } - talloc_free(call); + subreq = gensec_update_send(call, call->event_ctx, + auth->gensec_security, + call->in_auth_info.credentials); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; + } + tevent_req_set_callback(subreq, dcesrv_auth3_done, call); - /* we don't send a reply to a auth3 request, except by a - fault */ - return NT_STATUS_OK; + return dcesrv_conn_auth_wait_setup(conn); +} + +static void dcesrv_auth3_done(struct tevent_req *subreq) +{ + struct dcesrv_call_state *call = + tevent_req_callback_data(subreq, + struct dcesrv_call_state); + struct dcesrv_connection *conn = call->conn; + NTSTATUS status; + + status = gensec_update_recv(subreq, call, + &call->out_auth_info->credentials); + TALLOC_FREE(subreq); + + status = dcesrv_auth_complete(call, status); + if (!NT_STATUS_IS_OK(status)) { + /* + * we don't send a reply to a auth3 request, + * except by a fault. + * + * In anycase we mark the connection as + * invalid. + */ + call->conn->auth_state.auth_invalid = true; + if (call->fault_code != 0) { + status = dcesrv_fault_disconnect(call, call->fault_code); + dcesrv_conn_auth_wait_finished(conn, status); + return; + } + TALLOC_FREE(call); + dcesrv_conn_auth_wait_finished(conn, NT_STATUS_OK); + return; + } + + /* + * we don't send a reply to a auth3 request. + */ + TALLOC_FREE(call); + dcesrv_conn_auth_wait_finished(conn, NT_STATUS_OK); + return; } @@ -1089,6 +1520,11 @@ static NTSTATUS dcesrv_check_or_create_context(struct dcesrv_call_state *call, dcesrv_prepare_context_auth(call); + /* + * Multiplex is supported by default + */ + call->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED; + status = iface->bind(call, iface, if_version); call->context = NULL; if (!NT_STATUS_IS_OK(status)) { @@ -1178,17 +1614,21 @@ static NTSTATUS dcesrv_negotiate_contexts(struct dcesrv_call_state *call, return NT_STATUS_OK; } +static void dcesrv_alter_done(struct tevent_req *subreq); + /* handle a alter context request */ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) { + struct dcesrv_connection *conn = call->conn; NTSTATUS status; bool auth_ok = false; - struct ncacn_packet pkt; + struct ncacn_packet *pkt = &call->ack_pkt; uint32_t extra_flags = 0; - struct data_blob_list_item *rep = NULL; + struct dcesrv_auth *auth = &call->conn->auth_state; struct dcerpc_ack_ctx *ack_ctx_list = NULL; + struct tevent_req *subreq = NULL; size_t i; if (!call->conn->allow_alter) { @@ -1278,46 +1718,61 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) return dcesrv_fault_disconnect(call, DCERPC_FAULT_ACCESS_DENIED); } - dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); - pkt.auth_length = 0; - pkt.call_id = call->pkt.call_id; - pkt.ptype = DCERPC_PKT_ALTER_RESP; - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; - pkt.u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag; - pkt.u.alter_resp.max_recv_frag = call->conn->max_recv_frag; - pkt.u.alter_resp.assoc_group_id = call->conn->assoc_group->id; - pkt.u.alter_resp.secondary_address = ""; - pkt.u.alter_resp.num_results = call->pkt.u.alter.num_contexts; - pkt.u.alter_resp.ctx_list = ack_ctx_list; - pkt.u.alter_resp.auth_info = data_blob_null; - - status = dcesrv_auth_alter_ack(call, &pkt); + dcesrv_init_hdr(pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); + pkt->auth_length = 0; + pkt->call_id = call->pkt.call_id; + pkt->ptype = DCERPC_PKT_ALTER_RESP; + pkt->pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; + pkt->u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag; + pkt->u.alter_resp.max_recv_frag = call->conn->max_recv_frag; + pkt->u.alter_resp.assoc_group_id = call->conn->assoc_group->id; + pkt->u.alter_resp.secondary_address = ""; + pkt->u.alter_resp.num_results = call->pkt.u.alter.num_contexts; + pkt->u.alter_resp.ctx_list = ack_ctx_list; + pkt->u.alter_resp.auth_info = data_blob_null; + + status = dcesrv_auth_prepare_alter_ack(call, pkt); if (!NT_STATUS_IS_OK(status)) { return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR); } - rep = talloc_zero(call, struct data_blob_list_item); - if (!rep) { - return NT_STATUS_NO_MEMORY; + if (auth->auth_finished) { + return dcesrv_auth_reply(call); } - status = ncacn_push_auth(&rep->blob, call, &pkt, call->out_auth_info); - if (!NT_STATUS_IS_OK(status)) { - return status; + subreq = gensec_update_send(call, call->event_ctx, + auth->gensec_security, + call->in_auth_info.credentials); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; } + tevent_req_set_callback(subreq, dcesrv_alter_done, call); - dcerpc_set_frag_length(&rep->blob, rep->blob.length); + return dcesrv_conn_auth_wait_setup(conn); +} - DLIST_ADD_END(call->replies, rep); - dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST); +static void dcesrv_alter_done(struct tevent_req *subreq) +{ + struct dcesrv_call_state *call = + tevent_req_callback_data(subreq, + struct dcesrv_call_state); + struct dcesrv_connection *conn = call->conn; + NTSTATUS status; - if (call->conn->call_list && call->conn->call_list->replies) { - if (call->conn->transport.report_output_data) { - call->conn->transport.report_output_data(call->conn); - } + status = gensec_update_recv(subreq, call, + &call->out_auth_info->credentials); + TALLOC_FREE(subreq); + + status = dcesrv_auth_complete(call, status); + if (!NT_STATUS_IS_OK(status)) { + status = dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR); + dcesrv_conn_auth_wait_finished(conn, status); + return; } - return NT_STATUS_OK; + status = dcesrv_auth_reply(call); + dcesrv_conn_auth_wait_finished(conn, status); + return; } /* @@ -1390,7 +1845,6 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) dcerpc_binding_get_transport(endpoint->ep_description); struct ndr_pull *pull; NTSTATUS status; - struct dcesrv_connection_context *context; if (!call->conn->allow_request) { return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); @@ -1402,8 +1856,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC; } - context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id); - if (context == NULL) { + if (call->context == NULL) { return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF, DCERPC_PFC_FLAG_DID_NOT_EXECUTE); } @@ -1415,7 +1868,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) case DCERPC_AUTH_LEVEL_PRIVACY: break; default: - if (!context->allow_connect) { + if (!call->context->allow_connect) { char *addr; addr = tsocket_address_string(call->conn->remote_address, @@ -1424,7 +1877,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) DEBUG(2, ("%s: restrict auth_level_connect access " "to [%s] with auth[type=0x%x,level=0x%x] " "on [%s] from [%s]\n", - __func__, context->iface->name, + __func__, call->context->iface->name, call->conn->auth_state.auth_type, call->conn->auth_state.auth_level, derpc_transport_string_by_transport(transport), @@ -1434,7 +1887,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) break; } - if (call->conn->auth_state.auth_level < context->min_auth_level) { + if (call->conn->auth_state.auth_level < call->context->min_auth_level) { char *addr; addr = tsocket_address_string(call->conn->remote_address, call); @@ -1443,8 +1896,8 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) "to [%s] with auth[type=0x%x,level=0x%x] " "on [%s] from [%s]\n", __func__, - context->min_auth_level, - context->iface->name, + call->context->min_auth_level, + call->context->iface->name, call->conn->auth_state.auth_type, call->conn->auth_state.auth_level, derpc_transport_string_by_transport(transport), @@ -1457,7 +1910,6 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) pull->flags |= LIBNDR_FLAG_REF_ALLOC; - call->context = context; call->ndr_pull = pull; if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) { @@ -1476,13 +1928,14 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) } /* unravel the NDR for the packet */ - status = context->iface->ndr_pull(call, call, pull, &call->r); + status = call->context->iface->ndr_pull(call, call, pull, &call->r); if (!NT_STATUS_IS_OK(status)) { uint8_t extra_flags = 0; if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) { /* we got an unknown call */ DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n", - call->pkt.u.request.opnum, context->iface->name)); + call->pkt.u.request.opnum, + call->context->iface->name)); dcesrv_save_call(call, "unknown"); extra_flags |= DCERPC_PFC_FLAG_DID_NOT_EXECUTE; } else { @@ -1498,10 +1951,10 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) } /* call the dispatch function */ - status = context->iface->dispatch(call, call, call->r); + status = call->context->iface->dispatch(call, call, call->r); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("dcerpc fault in call %s:%02x - %s\n", - context->iface->name, + call->context->iface->name, call->pkt.u.request.opnum, dcerpc_errstr(pull, call->fault_code))); return dcesrv_fault(call, call->fault_code); @@ -1616,10 +2069,33 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, } if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) { + if (dce_conn->pending_call_list != NULL) { + /* + * concurrent requests are only allowed + * if DCERPC_PFC_FLAG_CONC_MPX was negotiated. + */ + if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) { + dcesrv_call_disconnect_after(call, + "dcesrv_auth_request - " + "existing pending call without CONN_MPX"); + return dcesrv_fault(call, + DCERPC_NCA_S_PROTO_ERROR); + } + } /* only one request is possible in the fragmented list */ if (dce_conn->incoming_fragmented_call_list != NULL) { - TALLOC_FREE(call); - call = dce_conn->incoming_fragmented_call_list; + if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) { + /* + * Without DCERPC_PFC_FLAG_CONC_MPX + * we need to return the FAULT on the + * already existing call. + * + * This is important to get the + * call_id and context_id right. + */ + TALLOC_FREE(call); + call = dce_conn->incoming_fragmented_call_list; + } dcesrv_call_disconnect_after(call, "dcesrv_auth_request - " "existing fragmented call"); @@ -1630,6 +2106,12 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, return dcesrv_fault_disconnect(call, DCERPC_FAULT_NO_CALL_ACTIVE); } + call->context = dcesrv_find_context(call->conn, + call->pkt.u.request.context_id); + if (call->context == NULL) { + return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF, + DCERPC_PFC_FLAG_DID_NOT_EXECUTE); + } } else { const struct dcerpc_request *nr = &call->pkt.u.request; const struct dcerpc_request *er = NULL; @@ -1887,11 +2369,9 @@ static int num_ep_servers; The 'name' can be later used by other backends to find the operations structure for this backend. - The 'type' is used to specify whether this is for a disk, printer or IPC$ share */ -_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server) +_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const struct dcesrv_endpoint_server *ep_server) { - const struct dcesrv_endpoint_server *ep_server = _ep_server; if (dcesrv_ep_server_byname(ep_server->name) != NULL) { /* its already registered! */ @@ -1935,7 +2415,7 @@ const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name) void dcerpc_server_init(struct loadparm_context *lp_ctx) { static bool initialized; -#define _MODULE_PROTO(init) extern NTSTATUS init(void); +#define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *); STATIC_dcerpc_server_MODULES_PROTO; init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES }; init_module_fn *shared_init; @@ -1947,8 +2427,8 @@ void dcerpc_server_init(struct loadparm_context *lp_ctx) shared_init = load_samba_modules(NULL, "dcerpc_server"); - run_init_functions(static_init); - run_init_functions(shared_init); + run_init_functions(NULL, static_init); + run_init_functions(NULL, shared_init); talloc_free(shared_init); } @@ -1983,6 +2463,10 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons srv_conn = talloc_get_type(dce_conn->transport.private_data, struct stream_connection); + dce_conn->wait_send = NULL; + dce_conn->wait_recv = NULL; + dce_conn->wait_private = NULL; + dce_conn->allow_bind = false; dce_conn->allow_auth3 = false; dce_conn->allow_alter = false; @@ -2000,11 +2484,11 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons return; } - DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n", + DEBUG(3,("dcesrv: terminating connection due to '%s' deferred due to pending calls\n", reason)); dce_conn->terminate = talloc_strdup(dce_conn, reason); if (dce_conn->terminate == NULL) { - dce_conn->terminate = "dcesrv: defered terminating connection - no memory"; + dce_conn->terminate = "dcesrv: deferred terminating connection - no memory"; } DLIST_ADD_END(dce_ctx->broken_connections, dce_conn); } @@ -2219,6 +2703,13 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn) } } + /* + * This fills in dcesrv_conn->endpoint with the endpoint + * associated with the socket. From this point on we know + * which (group of) services we are handling, but not the + * specific interface. + */ + status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, srv_conn, dcesrv_sock->endpoint, @@ -2250,7 +2741,6 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn) } if (transport == NCACN_NP) { - dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key; dcesrv_conn->stream = talloc_move(dcesrv_conn, &srv_conn->tstream); } else { @@ -2296,7 +2786,7 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn) struct tsocket_address *r = NULL; ret = tsocket_address_unix_from_path(dcesrv_conn, - "/root/ncalrpc_as_system", + AS_SYSTEM_MAGIC_PATH_TOKEN, &r); if (ret == -1) { status = map_nt_error_from_unix_common(errno); @@ -2312,8 +2802,6 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn) srv_conn->private_data = dcesrv_conn; - irpc_add_name(srv_conn->msg_ctx, "rpc_server"); - subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn, dcesrv_conn->event_ctx, dcesrv_conn->stream); @@ -2329,6 +2817,8 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn) return; } +static void dcesrv_conn_wait_done(struct tevent_req *subreq); + static void dcesrv_read_fragment_done(struct tevent_req *subreq) { struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq, @@ -2364,6 +2854,63 @@ static void dcesrv_read_fragment_done(struct tevent_req *subreq) return; } + /* + * This is used to block the connection during + * pending authentication. + */ + if (dce_conn->wait_send != NULL) { + subreq = dce_conn->wait_send(dce_conn, + dce_conn->event_ctx, + dce_conn->wait_private); + if (!subreq) { + status = NT_STATUS_NO_MEMORY; + dcesrv_terminate_connection(dce_conn, nt_errstr(status)); + return; + } + tevent_req_set_callback(subreq, dcesrv_conn_wait_done, dce_conn); + return; + } + + subreq = dcerpc_read_ncacn_packet_send(dce_conn, + dce_conn->event_ctx, + dce_conn->stream); + if (!subreq) { + status = NT_STATUS_NO_MEMORY; + dcesrv_terminate_connection(dce_conn, nt_errstr(status)); + return; + } + tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn); +} + +static void dcesrv_conn_wait_done(struct tevent_req *subreq) +{ + struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq, + struct dcesrv_connection); + struct dcesrv_context *dce_ctx = dce_conn->dce_ctx; + NTSTATUS status; + + if (dce_conn->terminate) { + /* + * if the current connection is broken + * we need to clean it up before any other connection + */ + dcesrv_terminate_connection(dce_conn, dce_conn->terminate); + dcesrv_cleanup_broken_connections(dce_ctx); + return; + } + + dcesrv_cleanup_broken_connections(dce_ctx); + + status = dce_conn->wait_recv(subreq); + dce_conn->wait_send = NULL; + dce_conn->wait_recv = NULL; + dce_conn->wait_private = NULL; + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + dcesrv_terminate_connection(dce_conn, nt_errstr(status)); + return; + } + subreq = dcerpc_read_ncacn_packet_send(dce_conn, dce_conn->event_ctx, dce_conn->stream); @@ -2400,7 +2947,9 @@ static const struct stream_server_ops dcesrv_stream_ops = { static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, struct loadparm_context *lp_ctx, struct dcesrv_endpoint *e, - struct tevent_context *event_ctx, const struct model_ops *model_ops) + struct tevent_context *event_ctx, + const struct model_ops *model_ops, + void *process_context) { struct dcesrv_socket_context *dcesrv_sock; uint16_t port = 1; @@ -2420,7 +2969,7 @@ static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, model_ops, &dcesrv_stream_ops, "unix", endpoint, &port, lpcfg_socket_options(lp_ctx), - dcesrv_sock); + dcesrv_sock, process_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", endpoint, nt_errstr(status))); @@ -2432,7 +2981,9 @@ static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, struct loadparm_context *lp_ctx, struct dcesrv_endpoint *e, - struct tevent_context *event_ctx, const struct model_ops *model_ops) + struct tevent_context *event_ctx, + const struct model_ops *model_ops, + void *process_context) { struct dcesrv_socket_context *dcesrv_sock; uint16_t port = 1; @@ -2474,7 +3025,7 @@ static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, model_ops, &dcesrv_stream_ops, "unix", full_path, &port, lpcfg_socket_options(lp_ctx), - dcesrv_sock); + dcesrv_sock, process_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n", endpoint, full_path, nt_errstr(status))); @@ -2485,7 +3036,9 @@ static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, struct loadparm_context *lp_ctx, struct dcesrv_endpoint *e, - struct tevent_context *event_ctx, const struct model_ops *model_ops) + struct tevent_context *event_ctx, + const struct model_ops *model_ops, + void *process_context) { struct dcesrv_socket_context *dcesrv_sock; NTSTATUS status; @@ -2507,7 +3060,7 @@ static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx, model_ops, &dcesrv_stream_ops, endpoint, - dcesrv_sock); + dcesrv_sock, process_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n", endpoint, nt_errstr(status))); @@ -2520,9 +3073,12 @@ static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, /* add a socket address to the list of events, one event per dcerpc endpoint */ -static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct tevent_context *event_ctx, const struct model_ops *model_ops, - const char *address) +static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, + struct dcesrv_endpoint *e, + struct tevent_context *event_ctx, + const struct model_ops *model_ops, + const char *address, + void *process_context) { struct dcesrv_socket_context *dcesrv_sock; uint16_t port = 0; @@ -2546,10 +3102,16 @@ static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct model_ops, &dcesrv_stream_ops, "ip", address, &port, lpcfg_socket_options(dce_ctx->lp_ctx), - dcesrv_sock); + dcesrv_sock, process_context); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", - address, port, nt_errstr(status))); + struct dcesrv_if_list *iface; + DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) for ", + address, port)); + for (iface = e->interface_list; iface; iface = iface->next) { + DEBUGADD(0, ("%s ", iface->iface.name)); + } + DEBUGADD(0, ("failed - %s", + nt_errstr(status))); return status; } @@ -2561,6 +3123,14 @@ static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n", port_str, nt_errstr(status))); return status; + } else { + struct dcesrv_if_list *iface; + DEBUG(4,("Successfully listening on ncacn_ip_tcp endpoint [%s]:[%s] for ", + address, port_str)); + for (iface = e->interface_list; iface; iface = iface->next) { + DEBUGADD(4, ("%s ", iface->iface.name)); + } + DEBUGADD(4, ("\n")); } return NT_STATUS_OK; @@ -2571,7 +3141,9 @@ static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, struct loadparm_context *lp_ctx, struct dcesrv_endpoint *e, - struct tevent_context *event_ctx, const struct model_ops *model_ops) + struct tevent_context *event_ctx, + const struct model_ops *model_ops, + void *process_context) { NTSTATUS status; @@ -2586,17 +3158,21 @@ static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, num_interfaces = iface_list_count(ifaces); for(i = 0; i < num_interfaces; i++) { const char *address = iface_list_n_ip(ifaces, i); - status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address); + status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, + model_ops, address, + process_context); NT_STATUS_NOT_OK_RETURN(status); } } else { char **wcard; - int i; - int num_binds = 0; + size_t i; + size_t num_binds = 0; wcard = iface_list_wildcard(dce_ctx); NT_STATUS_HAVE_NO_MEMORY(wcard); for (i=0; wcard[i]; i++) { - status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]); + status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, + model_ops, wcard[i], + process_context); if (NT_STATUS_IS_OK(status)) { num_binds++; } @@ -2614,23 +3190,28 @@ NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx, struct loadparm_context *lp_ctx, struct dcesrv_endpoint *e, struct tevent_context *event_ctx, - const struct model_ops *model_ops) + const struct model_ops *model_ops, + void *process_context) { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(e->ep_description); switch (transport) { case NCACN_UNIX_STREAM: - return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops); + return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, + model_ops, process_context); case NCALRPC: - return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops); + return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, + model_ops, process_context); case NCACN_IP_TCP: - return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops); + return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, + model_ops, process_context); case NCACN_NP: - return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops); + return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, + model_ops, process_context); default: return NT_STATUS_NOT_SUPPORTED; @@ -2663,3 +3244,11 @@ _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call { return dce_call->context->conn->auth_state.session_info->info->account_name; } + +/** + * retrieve session_info from a dce_call + */ +_PUBLIC_ struct auth_session_info *dcesrv_call_session_info(struct dcesrv_call_state *dce_call) +{ + return dce_call->context->conn->auth_state.session_info; +}