s4:rpc_server: make it possible to specify ncacn_np_secondary_endpoint
[gd/samba-autobuild/.git] / source4 / rpc_server / dcerpc_server.c
index 54ab2d0ec1dedaff7256f3002db59d7c86c1d360..75e1dfea1c786c9ebe4b184d8e97b1a47708ad9d 100644 (file)
@@ -65,18 +65,34 @@ static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context
 /*
   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)
@@ -93,13 +109,16 @@ 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;
        }
@@ -111,6 +130,7 @@ static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
+       assoc_group->transport = transport;
        assoc_group->id = id;
        assoc_group->dce_ctx = dce_ctx;
 
@@ -264,12 +284,14 @@ static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_conne
 */
 _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;
@@ -334,6 +356,22 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
                }
        }
 
+       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",
@@ -375,6 +413,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
                }
                ZERO_STRUCTP(ep);
                ep->ep_description = talloc_move(ep, &binding);
+               ep->ep_2nd_description = talloc_move(ep, &binding2);
                add_ep = true;
 
                /* add mgmt interface */
@@ -500,7 +539,7 @@ _PUBLIC_ NTSTATUS dcesrv_auth_session_key(struct dcesrv_call_state *call,
                                          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);
 }
 
@@ -517,6 +556,8 @@ _PUBLIC_ NTSTATUS dcesrv_transport_session_key(struct dcesrv_call_state *call,
        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;
        }
@@ -597,6 +638,12 @@ static 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->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);
@@ -666,7 +713,6 @@ static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call,
 
        call->conn->allow_bind = false;
        call->conn->allow_alter = false;
-       call->conn->allow_request = false;
 
        call->conn->default_auth_state->auth_invalid = true;
 
@@ -782,44 +828,31 @@ static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call)
                                        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;
@@ -838,18 +871,13 @@ _PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state
        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;
@@ -969,7 +997,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        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;
@@ -1015,11 +1043,9 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
         */
        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);
        }
 
        /*
@@ -1045,8 +1071,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        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);
@@ -1108,7 +1133,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
                                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;
        }
 
        /*
@@ -1182,29 +1207,19 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        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;
@@ -1518,7 +1533,6 @@ static NTSTATUS dcesrv_check_or_create_context(struct dcesrv_call_state *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);
@@ -1530,7 +1544,7 @@ static NTSTATUS dcesrv_check_or_create_context(struct dcesrv_call_state *call,
         */
        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 */
@@ -1805,8 +1819,7 @@ static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
 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,
@@ -1851,7 +1864,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
        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);
        }
 
@@ -2038,7 +2051,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
        /* 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);
                }
@@ -2476,7 +2489,6 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons
 
        dce_conn->allow_bind = false;
        dce_conn->allow_alter = false;
-       dce_conn->allow_request = false;
 
        dce_conn->default_auth_state->auth_invalid = true;
 
@@ -3233,6 +3245,7 @@ NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
 _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;
 }
 
@@ -3243,6 +3256,7 @@ _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
 {
        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;
 }
@@ -3253,6 +3267,7 @@ _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
 _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;
 }
 
@@ -3262,6 +3277,7 @@ _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call
 _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;
 }
 
@@ -3274,6 +3290,8 @@ _PUBLIC_ void dcesrv_call_auth_info(struct dcesrv_call_state *dce_call,
 {
        struct dcesrv_auth *auth = dce_call->auth_state;
 
+       SMB_ASSERT(auth->auth_finished);
+
        if (auth_type != NULL) {
                *auth_type = auth->auth_type;
        }