getncchanges: fix highest_usn off by one calculation in get_nc_changes_add_links()
[sfrench/samba-autobuild/.git] / source4 / rpc_server / common / reply.c
index d883317d6e4ad14f8727ef00a33148508eb1c404..ef2906e07242ad8f2b2bddb8577206adc91bb468 100644 (file)
@@ -38,6 +38,7 @@
 #include "lib/socket/socket.h"
 #include "smbd/process_model.h"
 #include "lib/messaging/irpc.h"
+#include "librpc/rpc/rpc_common.h"
 
 
 /*
@@ -66,13 +67,13 @@ static void dcesrv_call_set_list(struct dcesrv_call_state *call,
        case DCESRV_LIST_NONE:
                break;
        case DCESRV_LIST_CALL_LIST:
-               DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+               DLIST_ADD_END(call->conn->call_list, call);
                break;
        case DCESRV_LIST_FRAGMENTED_CALL_LIST:
-               DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
+               DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call);
                break;
        case DCESRV_LIST_PENDING_CALL_LIST:
-               DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
+               DLIST_ADD_END(call->conn->pending_call_list, call);
                break;
        }
 }
@@ -96,28 +97,33 @@ void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
 /*
   return a dcerpc fault
 */
-NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
+NTSTATUS dcesrv_fault_with_flags(struct dcesrv_call_state *call,
+                                uint32_t fault_code,
+                                uint8_t extra_flags)
 {
        struct ncacn_packet pkt;
        struct data_blob_list_item *rep;
-       uint8_t zeros[4];
        NTSTATUS status;
 
-       /* setup a bind_ack */
+       /* setup a fault */
        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_FAULT;
-       pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
-       pkt.u.fault.alloc_hint = 0;
-       pkt.u.fault.context_id = 0;
+       pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
+       pkt.u.fault.alloc_hint = 24;
+       if (call->context != NULL) {
+               pkt.u.fault.context_id = call->context->context_id;
+       } else {
+               pkt.u.fault.context_id = 0;
+       }
        pkt.u.fault.cancel_count = 0;
+       pkt.u.fault.flags = 0;
        pkt.u.fault.status = fault_code;
+       pkt.u.fault.reserved = 0;
+       pkt.u.fault.error_and_verifier = data_blob_null;
 
-       ZERO_STRUCT(zeros);
-       pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
-
-       rep = talloc(call, struct data_blob_list_item);
+       rep = talloc_zero(call, struct data_blob_list_item);
        if (!rep) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -129,7 +135,7 @@ NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
 
        dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-       DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+       DLIST_ADD_END(call->replies, rep);
        dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
        if (call->conn->call_list && call->conn->call_list->replies) {
@@ -141,7 +147,10 @@ NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
        return NT_STATUS_OK;
 }
 
-
+NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
+{
+       return dcesrv_fault_with_flags(call, fault_code, 0);
+}
 
 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
 {
@@ -182,31 +191,38 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
 
        /* we can write a full max_recv_frag size, minus the dcerpc
           request header size */
-       chunk_size = call->conn->cli_max_recv_frag;
+       chunk_size = call->conn->max_xmit_frag;
        chunk_size -= DCERPC_REQUEST_LENGTH;
-       if (call->conn->auth_state.auth_info &&
+       if (call->conn->auth_state.auth_finished &&
            call->conn->auth_state.gensec_security) {
+               size_t max_payload = chunk_size;
+
+               max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
+               max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
+
                sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
-                                          call->conn->cli_max_recv_frag);
+                                          max_payload);
                if (sig_size) {
                        chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
                        chunk_size -= sig_size;
                }
        }
-       chunk_size -= (chunk_size % 16);
+       chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
 
        do {
                uint32_t length;
                struct data_blob_list_item *rep;
                struct ncacn_packet pkt;
+               bool ok;
 
-               rep = talloc(call, struct data_blob_list_item);
+               rep = talloc_zero(call, struct data_blob_list_item);
                NT_STATUS_HAVE_NO_MEMORY(rep);
 
                length = MIN(chunk_size, stub.length);
 
                /* form the dcerpc response packet */
-               dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
+               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_RESPONSE;
@@ -218,18 +234,28 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
                        pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
                }
                pkt.u.response.alloc_hint = stub.length;
-               pkt.u.response.context_id = call->pkt.u.request.context_id;
+               /*
+                * bug for bug, feature for feature...
+                *
+                * Windows truncates the context_id with & 0xFF,
+                * so we do.
+                */
+               pkt.u.response.context_id = context->context_id & 0xFF;
                pkt.u.response.cancel_count = 0;
                pkt.u.response.stub_and_verifier.data = stub.data;
                pkt.u.response.stub_and_verifier.length = length;
 
-               if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
+               ok = dcesrv_auth_pkt_push(call, &rep->blob, sig_size,
+                                         DCERPC_RESPONSE_LENGTH,
+                                         &pkt.u.response.stub_and_verifier,
+                                         &pkt);
+               if (!ok) {
                        return dcesrv_fault(call, DCERPC_FAULT_OTHER);
                }
 
                dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-               DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+               DLIST_ADD_END(call->replies, rep);
 
                stub.data += length;
                stub.length -= length;
@@ -250,5 +276,12 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *c,
                                    DATA_BLOB *session_key)
 {
+       enum dcerpc_transport_t transport =
+               dcerpc_binding_get_transport(c->endpoint->ep_description);
+
+       if (transport != NCALRPC && transport != NCACN_UNIX_STREAM) {
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
        return dcerpc_generic_session_key(NULL, session_key);
 }