s4:rpc_server netgotiate max xmit size with RPC client
[ira/wip.git] / source4 / rpc_server / dcerpc_server.c
index d7bd7601f7c9ece8057f83a78668beb6cbbedf88..f2402605d94b9e8b3c8490c6444d385fe66d4cc1 100644 (file)
@@ -467,6 +467,12 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
+       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);
+               }
+       }
+
        return NT_STATUS_OK;    
 }
 
@@ -506,6 +512,12 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
+       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);
+               }
+       }
+
        return NT_STATUS_OK;    
 }
 
@@ -624,7 +636,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        }
 
        if (call->conn->cli_max_recv_frag == 0) {
-               call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
+               call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
        }
 
        if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
@@ -646,7 +658,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        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 = 0x2000;
+       pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
        pkt.u.bind_ack.max_recv_frag = 0x2000;
 
        /*
@@ -706,6 +718,12 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
+       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);
+               }
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -877,6 +895,12 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
        DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
+       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);
+               }
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -1111,17 +1135,17 @@ static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
 /*
   process some input to a dcerpc endpoint server.
 */
-NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
+NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
+                                    struct ncacn_packet *pkt,
+                                    DATA_BLOB blob)
 {
-       struct ndr_pull *ndr;
-       enum ndr_err_code ndr_err;
        NTSTATUS status;
        struct dcesrv_call_state *call;
-       DATA_BLOB blob;
 
        call = talloc_zero(dce_conn, struct dcesrv_call_state);
        if (!call) {
-               talloc_free(dce_conn->partial_input.data);
+               data_blob_free(&blob);
+               talloc_free(pkt);
                return NT_STATUS_NO_MEMORY;
        }
        call->conn              = dce_conn;
@@ -1131,43 +1155,19 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
        call->time              = timeval_current();
        call->list              = DCESRV_LIST_NONE;
 
-       talloc_set_destructor(call, dcesrv_call_dequeue);
-
-       blob = dce_conn->partial_input;
-       blob.length = dcerpc_get_frag_length(&blob);
-
-       ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
-       if (!ndr) {
-               talloc_free(dce_conn->partial_input.data);
-               talloc_free(call);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
-               ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
-       }
-
-       if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
-               ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
-       }
+       talloc_steal(call, pkt);
+       talloc_steal(call, blob.data);
+       call->pkt = *pkt;
 
-       ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               talloc_free(dce_conn->partial_input.data);
-               talloc_free(call);
-               return ndr_map_error2ntstatus(ndr_err);
-       }
+       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 &&
            !dcesrv_auth_request(call, &blob)) {
-               dce_partial_advance(dce_conn, blob.length);
                return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
        }
 
-       dce_partial_advance(dce_conn, blob.length);
-
        /* see if this is a continued packet */
        if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
            !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
@@ -1262,8 +1262,6 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
 */
 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
 {
-       NTSTATUS status;
-
        dce_conn->partial_input.data = talloc_realloc(dce_conn,
                                                      dce_conn->partial_input.data,
                                                      uint8_t,
@@ -1276,7 +1274,52 @@ _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BL
        dce_conn->partial_input.length += data->length;
 
        while (dce_full_packet(&dce_conn->partial_input)) {
-               status = dcesrv_input_process(dce_conn);
+               NTSTATUS status;
+               struct ndr_pull *ndr;
+               enum ndr_err_code ndr_err;
+               DATA_BLOB blob;
+               struct ncacn_packet *pkt;
+
+               blob = dce_conn->partial_input;
+               blob.length = dcerpc_get_frag_length(&blob);
+               blob = data_blob_talloc(dce_conn, blob.data, blob.length);
+               if (!blob.data) {
+                       data_blob_free(&dce_conn->partial_input);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               dce_partial_advance(dce_conn, blob.length);
+
+               pkt = talloc(dce_conn, struct ncacn_packet);
+               if (!pkt) {
+                       data_blob_free(&blob);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               ndr = ndr_pull_init_blob(&blob, pkt, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx));
+               if (!ndr) {
+                       data_blob_free(&blob);
+                       talloc_free(pkt);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
+                       ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+               }
+
+               if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
+                       ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+               }
+
+               ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+               TALLOC_FREE(ndr);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       data_blob_free(&blob);
+                       talloc_free(pkt);
+                       return ndr_map_error2ntstatus(ndr_err);
+               }
+
+               status = dcesrv_process_ncacn_packet(dce_conn, pkt, blob);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }