s4-dcerpc: fixed auth padding to be relative to the stub, not packet
[ira/wip.git] / source4 / rpc_server / dcesrv_auth.c
index e2e3b779489671d23f11a9e0122e3968889aa37b..59d8be3e24bdda1a58d226af1c3ccbf0cfb65cc0 100644 (file)
@@ -42,7 +42,7 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
        struct dcesrv_connection *dce_conn = call->conn;
        struct dcesrv_auth *auth = &dce_conn->auth_state;
        NTSTATUS status;
-       enum ndr_err_code ndr_err;
+       uint32_t auth_length;
 
        if (pkt->u.bind.auth_info.length == 0) {
                dce_conn->auth_state.auth_info = NULL;
@@ -54,14 +54,9 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
                return false;
        }
 
-       ndr_err = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
-                                      call, NULL,
-                                      dce_conn->auth_state.auth_info,
-                                      (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               return false;
-       }
-
+       status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
+                                         dce_conn->auth_state.auth_info,
+                                         &auth_length, false);
        server_credentials 
                = cli_credentials_init(call);
        if (!server_credentials) {
@@ -155,7 +150,7 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
        struct ncacn_packet *pkt = &call->pkt;
        struct dcesrv_connection *dce_conn = call->conn;
        NTSTATUS status;
-       enum ndr_err_code ndr_err;
+       uint32_t auth_length;
 
        /* We can't work without an existing gensec state, and an new blob to feed it */
        if (!dce_conn->auth_state.auth_info ||
@@ -164,11 +159,9 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
                return false;
        }
 
-       ndr_err = ndr_pull_struct_blob(&pkt->u.auth3.auth_info,
-                                      call, NULL,
-                                      dce_conn->auth_state.auth_info,
-                                      (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+       status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
+                                         dce_conn->auth_state.auth_info, &auth_length, true);
+       if (!NT_STATUS_IS_OK(status)) {
                return false;
        }
 
@@ -205,7 +198,8 @@ bool dcesrv_auth_alter(struct dcesrv_call_state *call)
 {
        struct ncacn_packet *pkt = &call->pkt;
        struct dcesrv_connection *dce_conn = call->conn;
-       enum ndr_err_code ndr_err;
+       NTSTATUS status;
+       uint32_t auth_length;
 
        /* on a pure interface change there is no auth blob */
        if (pkt->u.alter.auth_info.length == 0) {
@@ -222,11 +216,10 @@ bool dcesrv_auth_alter(struct dcesrv_call_state *call)
                return false;
        }
 
-       ndr_err = ndr_pull_struct_blob(&pkt->u.alter.auth_info,
-                                      call, NULL,
-                                      dce_conn->auth_state.auth_info,
-                                      (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+       status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info,
+                                         dce_conn->auth_state.auth_info,
+                                         &auth_length, true);
+       if (!NT_STATUS_IS_OK(status)) {
                return false;
        }
 
@@ -286,11 +279,9 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
 {
        struct ncacn_packet *pkt = &call->pkt;
        struct dcesrv_connection *dce_conn = call->conn;
-       DATA_BLOB auth_blob;
        struct dcerpc_auth auth;
-       struct ndr_pull *ndr;
        NTSTATUS status;
-       enum ndr_err_code ndr_err;
+       uint32_t auth_length;
        size_t hdr_size = DCERPC_REQUEST_LENGTH;
 
        if (!dce_conn->auth_state.auth_info ||
@@ -298,6 +289,10 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
                return true;
        }
 
+       if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
+               hdr_size += 16;
+       }
+
        switch (dce_conn->auth_state.auth_info->auth_level) {
        case DCERPC_AUTH_LEVEL_PRIVACY:
        case DCERPC_AUTH_LEVEL_INTEGRITY:
@@ -318,38 +313,14 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
                return false;
        }
 
-       auth_blob.length = 8 + pkt->auth_length;
-
-       /* check for a valid length */
-       if (pkt->u.request.stub_and_verifier.length < auth_blob.length) {
-               return false;
-       }
-
-       auth_blob.data = 
-               pkt->u.request.stub_and_verifier.data + 
-               pkt->u.request.stub_and_verifier.length - auth_blob.length;
-       pkt->u.request.stub_and_verifier.length -= auth_blob.length;
-
-       /* pull the auth structure */
-       ndr = ndr_pull_init_blob(&auth_blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
-       if (!ndr) {
+       status = dcerpc_pull_auth_trailer(pkt, call,
+                                         &pkt->u.request.stub_and_verifier,
+                                         &auth, &auth_length, false);
+       if (!NT_STATUS_IS_OK(status)) {
                return false;
        }
 
-       if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
-               ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
-       }
-
-       if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
-               ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
-               hdr_size += 16;
-       }
-
-       ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               talloc_free(ndr);
-               return false;
-       }
+       pkt->u.request.stub_and_verifier.length -= auth_length;
 
        /* check signature or unseal the packet */
        switch (dce_conn->auth_state.auth_info->auth_level) {
@@ -388,11 +359,9 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
 
        /* remove the indicated amount of padding */
        if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
-               talloc_free(ndr);
                return false;
        }
        pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
-       talloc_free(ndr);
 
        return NT_STATUS_IS_OK(status);
 }
@@ -453,7 +422,11 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
                return false;
        }
 
-       /* pad to 16 byte multiple, match win2k3 */
+       /* pad to 16 byte multiple in the payload portion of the
+          packet. This matches what w2k3 does. Note that we can't use
+          ndr_push_align() as that is relative to the start of the
+          whole packet, whereas w2k8 wants it relative to the start
+          of the stub */
        dce_conn->auth_state.auth_info->auth_pad_length =
                (16 - (pkt->u.response.stub_and_verifier.length & 15)) & 15;
        ndr_err = ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
@@ -513,27 +486,24 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call,
                break;
        }
 
-       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)) {
+               return false;
+       }       
 
-       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 (creds2.length != sig_size) {
+               DEBUG(3,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
+                        (unsigned)creds2.length, (uint32_t)sig_size,
+                        (unsigned)dce_conn->auth_state.auth_info->auth_pad_length,
+                        (unsigned)pkt->u.response.stub_and_verifier.length));
+               dcerpc_set_frag_length(blob, blob->length + creds2.length);
+               dcerpc_set_auth_length(blob, creds2.length);
        }
 
-       if (!NT_STATUS_IS_OK(status)) {
+       if (!data_blob_append(call, blob, creds2.data, creds2.length)) {
+               status = NT_STATUS_NO_MEMORY;
                return false;
-       }       
+       }
+       data_blob_free(&creds2);
 
        return true;
 }