rpc_server: don't send auth trailers in level connect
authorStefan Metzmacher <metze@samba.org>
Fri, 12 Sep 2008 13:47:02 +0000 (15:47 +0200)
committerStefan Metzmacher <metze@samba.org>
Sat, 13 Sep 2008 18:37:12 +0000 (20:37 +0200)
Also ignore auth trailers in level connect on receive.

This fixes [krb5,connect] against windows.

TODO: maybe the gensec mech need to decide if signatures
      are needed in level connect.

metze

source/rpc_server/dcerpc_server.c
source/rpc_server/dcesrv_auth.c

index fa7b8d26f5c72fe0c57ffb6d47e1f957da898b84..e5f59d0cf946c65dcdb6638fda6a122115034931 100644 (file)
@@ -951,13 +951,16 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
           request header size */
        chunk_size = call->conn->cli_max_recv_frag;
        chunk_size -= DCERPC_REQUEST_LENGTH;
-       if (call->conn->auth_state.gensec_security) {
-               chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
+       if (call->conn->auth_state.auth_info &&
+           call->conn->auth_state.gensec_security) {
                sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
                                           call->conn->cli_max_recv_frag);
-               chunk_size -= sig_size;
-               chunk_size -= (chunk_size % 16);
+               if (sig_size) {
+                       chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
+                       chunk_size -= sig_size;
+               }
        }
+       chunk_size -= (chunk_size % 16);
 
        do {
                uint32_t length;
index 3a7f2420b38ad45d8e467667f24fa043b3bfd878..16bf4eb7ed9bf8c6ef04356e106fe8939bd951a8 100644 (file)
@@ -275,33 +275,6 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack
        return status;
 }
 
-/*
-  generate a CONNECT level verifier
-*/
-static NTSTATUS dcesrv_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
-{
-       *blob = data_blob_talloc(mem_ctx, NULL, 16);
-       if (blob->data == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       SIVAL(blob->data, 0, 1);
-       memset(blob->data+4, 0, 12);
-       return NT_STATUS_OK;
-}
-
-/*
-  generate a CONNECT level verifier
-*/
-static NTSTATUS dcesrv_check_connect_verifier(DATA_BLOB *blob)
-{
-       if (blob->length != 16 ||
-           IVAL(blob->data, 0) != 1) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-       return NT_STATUS_OK;
-}
-
-
 /*
   check credentials on a request
 */
@@ -320,6 +293,26 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
                return true;
        }
 
+       switch (dce_conn->auth_state.auth_info->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               break;
+
+       case DCERPC_AUTH_LEVEL_CONNECT:
+               if (pkt->auth_length != 0) {
+                       break;
+               }
+               return true;
+       case DCERPC_AUTH_LEVEL_NONE:
+               if (pkt->auth_length != 0) {
+                       return false;
+               }
+               return true;
+
+       default:
+               return false;
+       }
+
        auth_blob.length = 8 + pkt->auth_length;
 
        /* check for a valid length */
@@ -374,7 +367,8 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
                break;
 
        case DCERPC_AUTH_LEVEL_CONNECT:
-               status = dcesrv_check_connect_verifier(&auth.credentials);
+               /* for now we ignore possible signatures here */
+               status = NT_STATUS_OK;
                break;
 
        default:
@@ -409,9 +403,30 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
        DATA_BLOB creds2;
 
        /* non-signed packets are simple */
-       if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
+       if (sig_size == 0) {
+               status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL);
+               return NT_STATUS_IS_OK(status);
+       }
+
+       switch (dce_conn->auth_state.auth_info->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               break;
+
+       case DCERPC_AUTH_LEVEL_CONNECT:
+               /*
+                * TODO: let the gensec mech decide if it wants to generate a signature
+                *       that might be needed for schannel...
+                */
                status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL);
                return NT_STATUS_IS_OK(status);
+
+       case DCERPC_AUTH_LEVEL_NONE:
+               status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL);
+               return NT_STATUS_IS_OK(status);
+
+       default:
+               return false;
        }
 
        ndr = ndr_push_init_ctx(call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx));
@@ -439,21 +454,8 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
        payload_length = pkt->u.response.stub_and_verifier.length +
                dce_conn->auth_state.auth_info->auth_pad_length;
 
-       if (dce_conn->auth_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
-               status = dcesrv_connect_verifier(call,
-                                                &dce_conn->auth_state.auth_info->credentials);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return false;
-               }
-       } else {
-
-               /* We hope this length is accruate.  If must be if the
-                * GENSEC mech does AEAD signing of the packet
-                * headers */
-               dce_conn->auth_state.auth_info->credentials
-                       = data_blob_talloc(call, NULL, sig_size);
-               data_blob_clear(&dce_conn->auth_state.auth_info->credentials);
-       }
+       /* we start without signature, it will appended later */
+       dce_conn->auth_state.auth_info->credentials = data_blob(NULL, 0);
 
        /* add the auth verifier */
        ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
@@ -465,14 +467,14 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
        /* extract the whole packet as a blob */
        *blob = ndr_push_blob(ndr);
 
-       /* fill in the fragment length and auth_length, we can't fill
-          in these earlier as we don't know the signature length (it
-          could be variable length) */
-       dcerpc_set_frag_length(blob, blob->length);
-
-       /* We hope this value is accruate.  If must be if the GENSEC
-        * mech does AEAD signing of the packet headers */
-       dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
+       /*
+        * Setup the frag and auth length in the packet buffer.
+        * This is needed if the GENSEC mech does AEAD signing
+        * of the packet headers. The signature itself will be
+        * appended later.
+        */
+       dcerpc_set_frag_length(blob, blob->length + sig_size);
+       dcerpc_set_auth_length(blob, sig_size);
 
        /* sign or seal the packet */
        switch (dce_conn->auth_state.auth_info->auth_level) {
@@ -482,22 +484,8 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
                                            ndr->data + DCERPC_REQUEST_LENGTH, 
                                            payload_length,
                                            blob->data,
-                                           blob->length - dce_conn->auth_state.auth_info->credentials.length,
+                                           blob->length,
                                            &creds2);
-
-               if (NT_STATUS_IS_OK(status)) {
-                       blob->length -= dce_conn->auth_state.auth_info->credentials.length;
-                       if (!data_blob_append(call, blob, creds2.data, creds2.length))
-                               status = NT_STATUS_NO_MEMORY;
-                       else
-                               status = NT_STATUS_OK;
-               }
-
-               /* If we did AEAD signing of the packet headers, then we hope
-                * this value didn't change... */
-               dcerpc_set_auth_length(blob, creds2.length);
-               dcerpc_set_frag_length(blob, dcerpc_get_frag_length(blob)+creds2.length);
-               data_blob_free(&creds2);
                break;
 
        case DCERPC_AUTH_LEVEL_INTEGRITY:
@@ -506,24 +494,8 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
                                            ndr->data + DCERPC_REQUEST_LENGTH, 
                                            payload_length,
                                            blob->data,
-                                           blob->length - dce_conn->auth_state.auth_info->credentials.length,
+                                           blob->length,
                                            &creds2);
-               if (NT_STATUS_IS_OK(status)) {
-                       blob->length -= dce_conn->auth_state.auth_info->credentials.length;
-                       if (!data_blob_append(call, blob, creds2.data, creds2.length))
-                               status = NT_STATUS_NO_MEMORY;
-                       else
-                               status = NT_STATUS_OK;
-               }
-
-               /* If we did AEAD signing of the packet headers, then we hope
-                * this value didn't change... */
-               dcerpc_set_auth_length(blob, creds2.length);
-               dcerpc_set_frag_length(blob, dcerpc_get_frag_length(blob)+creds2.length);
-               data_blob_free(&creds2);
-               break;
-
-       case DCERPC_AUTH_LEVEL_CONNECT:
                break;
 
        default:
@@ -531,7 +503,23 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
                break;
        }
 
-       data_blob_free(&dce_conn->auth_state.auth_info->credentials);
+       if (NT_STATUS_IS_OK(status)) {
+               if (creds2.length != sig_size) {
+                       DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
+                               creds2.length, (uint32_t)sig_size,
+                               dce_conn->auth_state.auth_info->auth_pad_length,
+                               pkt->u.response.stub_and_verifier.length));
+                       data_blob_free(&creds2);
+                       status = NT_STATUS_INTERNAL_ERROR;
+               }
+       }
+
+       if (NT_STATUS_IS_OK(status)) {
+               if (!data_blob_append(call, blob, creds2.data, creds2.length)) {
+                       status = NT_STATUS_NO_MEMORY;
+               }
+               data_blob_free(&creds2);
+       }
 
        if (!NT_STATUS_IS_OK(status)) {
                return false;